siyuan/kernel/av/calc.go

1904 lines
73 KiB
Go

// SiYuan - Refactor your thinking
// Copyright (c) 2020-present, b3log.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package av
import (
"math"
"sort"
"github.com/siyuan-note/siyuan/kernel/util"
)
// FieldCalc 描述了字段计算操作和结果的结构。
type FieldCalc struct {
Operator CalcOperator `json:"operator"` // 计算操作符
Result *Value `json:"result"` // 计算结果
}
type CalcOperator string
const (
CalcOperatorNone CalcOperator = ""
CalcOperatorUniqueValues CalcOperator = "Unique values"
CalcOperatorCountAll CalcOperator = "Count all"
CalcOperatorCountValues CalcOperator = "Count values"
CalcOperatorCountUniqueValues CalcOperator = "Count unique values"
CalcOperatorCountEmpty CalcOperator = "Count empty"
CalcOperatorCountNotEmpty CalcOperator = "Count not empty"
CalcOperatorPercentEmpty CalcOperator = "Percent empty"
CalcOperatorPercentNotEmpty CalcOperator = "Percent not empty"
CalcOperatorPercentUniqueValues CalcOperator = "Percent unique values"
CalcOperatorSum CalcOperator = "Sum"
CalcOperatorAverage CalcOperator = "Average"
CalcOperatorMedian CalcOperator = "Median"
CalcOperatorMin CalcOperator = "Min"
CalcOperatorMax CalcOperator = "Max"
CalcOperatorRange CalcOperator = "Range"
CalcOperatorEarliest CalcOperator = "Earliest"
CalcOperatorLatest CalcOperator = "Latest"
CalcOperatorChecked CalcOperator = "Checked"
CalcOperatorUnchecked CalcOperator = "Unchecked"
CalcOperatorPercentChecked CalcOperator = "Percent checked"
CalcOperatorPercentUnchecked CalcOperator = "Percent unchecked"
)
func Calc(viewable Viewable, attrView *AttributeView) {
collection := viewable.(Collection)
// 字段计算
for i, field := range collection.GetFields() {
calc := field.GetCalc()
if nil == calc || CalcOperatorNone == calc.Operator {
continue
}
calcField(collection, field, i)
}
// 分组计算
if groupCalc := viewable.GetGroupCalc(); nil != groupCalc {
if groupCalcKey, _ := attrView.GetKey(groupCalc.Field); nil != groupCalcKey {
if field, fieldIndex := collection.GetField(groupCalcKey.ID); nil != field {
var calcResult *GroupCalc
if calc := field.GetCalc(); nil != calc && field.GetID() == groupCalcKey.ID {
// 直接使用字段计算结果
calcResult = &GroupCalc{Field: groupCalcKey.ID, FieldCalc: calc}
}
if nil == calcResult {
// 在字段上设置计算规则,使用字段结算结果作为分组计算结果,最后再清除字段上的计算规则
field.SetCalc(groupCalc.FieldCalc)
calcField(collection, field, fieldIndex)
calcResult = &GroupCalc{Field: groupCalcKey.ID, FieldCalc: field.GetCalc()}
field.SetCalc(nil)
}
viewable.SetGroupCalc(calcResult)
}
}
}
}
func calcField(collection Collection, field Field, fieldIndex int) {
switch field.GetType() {
case KeyTypeBlock:
calcFieldBlock(collection, field, fieldIndex)
case KeyTypeText:
calcFieldText(collection, field, fieldIndex)
case KeyTypeNumber:
calcFieldNumber(collection, field, fieldIndex)
case KeyTypeDate:
calcFieldDate(collection, field, fieldIndex)
case KeyTypeSelect:
calcFieldSelect(collection, field, fieldIndex)
case KeyTypeMSelect:
calcFieldMSelect(collection, field, fieldIndex)
case KeyTypeURL:
calcFieldURL(collection, field, fieldIndex)
case KeyTypeEmail:
calcFieldEmail(collection, field, fieldIndex)
case KeyTypePhone:
calcFieldPhone(collection, field, fieldIndex)
case KeyTypeMAsset:
calcFieldMAsset(collection, field, fieldIndex)
case KeyTypeTemplate:
calcFieldTemplate(collection, field, fieldIndex)
case KeyTypeCreated:
calcFieldCreated(collection, field, fieldIndex)
case KeyTypeUpdated:
calcFieldUpdated(collection, field, fieldIndex)
case KeyTypeCheckbox:
calcFieldCheckbox(collection, field, fieldIndex)
case KeyTypeRelation:
calcFieldRelation(collection, field, fieldIndex)
case KeyTypeRollup:
calcFieldRollup(collection, field, fieldIndex)
}
}
func calcFieldTemplate(collection Collection, field Field, fieldIndex int) {
calc := field.GetCalc()
switch calc.Operator {
case CalcOperatorCountAll:
calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
case CalcOperatorCountValues:
countValues := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Template && "" != values[fieldIndex].Template.Content {
countValues++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
case CalcOperatorCountUniqueValues:
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Template && "" != values[fieldIndex].Template.Content {
if !uniqueValues[values[fieldIndex].Template.Content] {
uniqueValues[values[fieldIndex].Template.Content] = true
countUniqueValues++
}
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
case CalcOperatorCountEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].Template || "" == values[fieldIndex].Template.Content {
countEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
case CalcOperatorCountNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Template && "" != values[fieldIndex].Template.Content {
countNotEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
case CalcOperatorPercentEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].Template || "" == values[fieldIndex].Template.Content {
countEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Template && "" != values[fieldIndex].Template.Content {
countNotEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentUniqueValues:
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Template && "" != values[fieldIndex].Template.Content {
if !uniqueValues[values[fieldIndex].Template.Content] {
uniqueValues[values[fieldIndex].Template.Content] = true
countUniqueValues++
}
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorSum:
sum := 0.0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Template && "" != values[fieldIndex].Template.Content {
val, _ := util.Convert2Float(values[fieldIndex].Template.Content)
sum += val
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(sum, field.GetNumberFormat())}
case CalcOperatorAverage:
sum := 0.0
count := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Template && "" != values[fieldIndex].Template.Content {
val, _ := util.Convert2Float(values[fieldIndex].Template.Content)
sum += val
count++
}
}
if 0 != count {
calc.Result = &Value{Number: NewFormattedValueNumber(sum/float64(count), field.GetNumberFormat())}
}
case CalcOperatorMedian:
calcValues := []float64{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Template && "" != values[fieldIndex].Template.Content {
val, _ := util.Convert2Float(values[fieldIndex].Template.Content)
calcValues = append(calcValues, val)
}
}
sort.Float64s(calcValues)
if len(calcValues) > 0 {
if len(calcValues)%2 == 0 {
calc.Result = &Value{Number: NewFormattedValueNumber((calcValues[len(calcValues)/2-1]+calcValues[len(calcValues)/2])/2, field.GetNumberFormat())}
} else {
calc.Result = &Value{Number: NewFormattedValueNumber(calcValues[len(calcValues)/2], field.GetNumberFormat())}
}
}
case CalcOperatorMin:
minVal := math.MaxFloat64
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Template && "" != values[fieldIndex].Template.Content {
val, _ := util.Convert2Float(values[fieldIndex].Template.Content)
if val < minVal {
minVal = val
}
}
}
if math.MaxFloat64 != minVal {
calc.Result = &Value{Number: NewFormattedValueNumber(minVal, field.GetNumberFormat())}
}
case CalcOperatorMax:
maxVal := -math.MaxFloat64
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Template && "" != values[fieldIndex].Template.Content {
val, _ := util.Convert2Float(values[fieldIndex].Template.Content)
if val > maxVal {
maxVal = val
}
}
}
if -math.MaxFloat64 != maxVal {
calc.Result = &Value{Number: NewFormattedValueNumber(maxVal, field.GetNumberFormat())}
}
case CalcOperatorRange:
minVal := math.MaxFloat64
maxVal := -math.MaxFloat64
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Template && "" != values[fieldIndex].Template.Content {
val, _ := util.Convert2Float(values[fieldIndex].Template.Content)
if val < minVal {
minVal = val
}
if val > maxVal {
maxVal = val
}
}
}
if math.MaxFloat64 != minVal && -math.MaxFloat64 != maxVal {
calc.Result = &Value{Number: NewFormattedValueNumber(maxVal-minVal, field.GetNumberFormat())}
}
}
}
func calcFieldMAsset(collection Collection, field Field, fieldIndex int) {
calc := field.GetCalc()
switch calc.Operator {
case CalcOperatorCountAll:
calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
case CalcOperatorCountValues:
countValues := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].MAsset && 0 < len(values[fieldIndex].MAsset) {
countValues += len(values[fieldIndex].MAsset)
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
case CalcOperatorCountUniqueValues:
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].MAsset && 0 < len(values[fieldIndex].MAsset) {
for _, sel := range values[fieldIndex].MAsset {
if _, ok := uniqueValues[sel.Content]; !ok {
uniqueValues[sel.Content] = true
countUniqueValues++
}
}
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
case CalcOperatorCountEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].MAsset || 0 == len(values[fieldIndex].MAsset) {
countEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
case CalcOperatorCountNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].MAsset && 0 < len(values[fieldIndex].MAsset) {
countNotEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
case CalcOperatorPercentEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].MAsset || 0 == len(values[fieldIndex].MAsset) {
countEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].MAsset && 0 < len(values[fieldIndex].MAsset) {
countNotEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentUniqueValues:
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].MAsset && 0 < len(values[fieldIndex].MAsset) {
for _, sel := range values[fieldIndex].MAsset {
if _, ok := uniqueValues[sel.Content]; !ok {
uniqueValues[sel.Content] = true
countUniqueValues++
}
}
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
}
}
func calcFieldMSelect(collection Collection, field Field, fieldIndex int) {
calc := field.GetCalc()
switch calc.Operator {
case CalcOperatorCountAll:
calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
case CalcOperatorCountValues:
countValues := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].MSelect && 0 < len(values[fieldIndex].MSelect) {
countValues += len(values[fieldIndex].MSelect)
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
case CalcOperatorCountUniqueValues:
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].MSelect && 0 < len(values[fieldIndex].MSelect) {
for _, sel := range values[fieldIndex].MSelect {
if _, ok := uniqueValues[sel.Content]; !ok {
uniqueValues[sel.Content] = true
countUniqueValues++
}
}
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
case CalcOperatorCountEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].MSelect || 0 == len(values[fieldIndex].MSelect) {
countEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
case CalcOperatorCountNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].MSelect && 0 < len(values[fieldIndex].MSelect) {
countNotEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
case CalcOperatorPercentEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].MSelect || 0 == len(values[fieldIndex].MSelect) {
countEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].MSelect && 0 < len(values[fieldIndex].MSelect) {
countNotEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentUniqueValues:
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].MSelect && 0 < len(values[fieldIndex].MSelect) {
for _, sel := range values[fieldIndex].MSelect {
if _, ok := uniqueValues[sel.Content]; !ok {
uniqueValues[sel.Content] = true
countUniqueValues++
}
}
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
}
}
func calcFieldSelect(collection Collection, field Field, fieldIndex int) {
calc := field.GetCalc()
switch calc.Operator {
case CalcOperatorCountAll:
calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
case CalcOperatorCountValues:
countValues := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].MSelect && 0 < len(values[fieldIndex].MSelect) && nil != values[fieldIndex].MSelect[0] && "" != values[fieldIndex].MSelect[0].Content {
countValues++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
case CalcOperatorCountUniqueValues:
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].MSelect && 0 < len(values[fieldIndex].MSelect) && nil != values[fieldIndex].MSelect[0] && "" != values[fieldIndex].MSelect[0].Content {
if _, ok := uniqueValues[values[fieldIndex].MSelect[0].Content]; !ok {
uniqueValues[values[fieldIndex].MSelect[0].Content] = true
countUniqueValues++
}
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
case CalcOperatorCountEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].MSelect || 1 > len(values[fieldIndex].MSelect) || nil == values[fieldIndex].MSelect[0] || "" == values[fieldIndex].MSelect[0].Content {
countEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
case CalcOperatorCountNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].MSelect && 0 < len(values[fieldIndex].MSelect) && nil != values[fieldIndex].MSelect[0] && "" != values[fieldIndex].MSelect[0].Content {
countNotEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
case CalcOperatorPercentEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].MSelect || 1 > len(values[fieldIndex].MSelect) || nil == values[fieldIndex].MSelect[0] || "" == values[fieldIndex].MSelect[0].Content {
countEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].MSelect && 0 < len(values[fieldIndex].MSelect) && nil != values[fieldIndex].MSelect[0] && "" != values[fieldIndex].MSelect[0].Content {
countNotEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentUniqueValues:
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].MSelect && 0 < len(values[fieldIndex].MSelect) && nil != values[fieldIndex].MSelect[0] && "" != values[fieldIndex].MSelect[0].Content {
if _, ok := uniqueValues[values[fieldIndex].MSelect[0].Content]; !ok {
uniqueValues[values[fieldIndex].MSelect[0].Content] = true
countUniqueValues++
}
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
}
}
func calcFieldDate(collection Collection, field Field, fieldIndex int) {
calc := field.GetCalc()
switch calc.Operator {
case CalcOperatorCountAll:
calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
case CalcOperatorCountValues:
countValues := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Date && values[fieldIndex].Date.IsNotEmpty {
countValues++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
case CalcOperatorCountUniqueValues:
countUniqueValues := 0
uniqueValues := map[int64]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Date && values[fieldIndex].Date.IsNotEmpty {
if _, ok := uniqueValues[values[fieldIndex].Date.Content]; !ok {
countUniqueValues++
uniqueValues[values[fieldIndex].Date.Content] = true
}
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
case CalcOperatorCountEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].Date || !values[fieldIndex].Date.IsNotEmpty {
countEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
case CalcOperatorCountNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Date && values[fieldIndex].Date.IsNotEmpty {
countNotEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
case CalcOperatorPercentEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].Date || !values[fieldIndex].Date.IsNotEmpty {
countEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Date && values[fieldIndex].Date.IsNotEmpty {
countNotEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentUniqueValues:
countUniqueValues := 0
uniqueValues := map[int64]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Date && values[fieldIndex].Date.IsNotEmpty {
if _, ok := uniqueValues[values[fieldIndex].Date.Content]; !ok {
countUniqueValues++
uniqueValues[values[fieldIndex].Date.Content] = true
}
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorEarliest:
earliest := int64(0)
var isNotTime, hasEndDate bool
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Date && values[fieldIndex].Date.IsNotEmpty {
if 0 == earliest || earliest > values[fieldIndex].Date.Content {
earliest = values[fieldIndex].Date.Content
isNotTime = values[fieldIndex].Date.IsNotTime
hasEndDate = values[fieldIndex].Date.HasEndDate
}
}
}
if 0 != earliest {
calc.Result = &Value{Date: NewFormattedValueDate(earliest, 0, DateFormatNone, isNotTime, hasEndDate)}
}
case CalcOperatorLatest:
latest := int64(0)
var isNotTime, hasEndDate bool
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Date && values[fieldIndex].Date.IsNotEmpty {
if 0 == latest || latest < values[fieldIndex].Date.Content {
latest = values[fieldIndex].Date.Content
isNotTime = values[fieldIndex].Date.IsNotTime
hasEndDate = values[fieldIndex].Date.HasEndDate
}
}
}
if 0 != latest {
calc.Result = &Value{Date: NewFormattedValueDate(latest, 0, DateFormatNone, isNotTime, hasEndDate)}
}
case CalcOperatorRange:
earliest := int64(0)
latest := int64(0)
var isNotTime, hasEndDate bool
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Date && values[fieldIndex].Date.IsNotEmpty {
if 0 == earliest || earliest > values[fieldIndex].Date.Content {
earliest = values[fieldIndex].Date.Content
isNotTime = values[fieldIndex].Date.IsNotTime
hasEndDate = values[fieldIndex].Date.HasEndDate
}
if 0 == latest || latest < values[fieldIndex].Date.Content {
latest = values[fieldIndex].Date.Content
isNotTime = values[fieldIndex].Date.IsNotTime
hasEndDate = values[fieldIndex].Date.HasEndDate
}
}
}
if 0 != earliest && 0 != latest {
calc.Result = &Value{Date: NewFormattedValueDate(earliest, latest, DateFormatDuration, isNotTime, hasEndDate)}
}
}
}
func calcFieldNumber(collection Collection, field Field, fieldIndex int) {
calc := field.GetCalc()
switch calc.Operator {
case CalcOperatorCountAll:
calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
case CalcOperatorCountValues:
countValues := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Number && values[fieldIndex].Number.IsNotEmpty {
countValues++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
case CalcOperatorCountUniqueValues:
countUniqueValues := 0
uniqueValues := map[float64]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Number && values[fieldIndex].Number.IsNotEmpty {
if !uniqueValues[values[fieldIndex].Number.Content] {
uniqueValues[values[fieldIndex].Number.Content] = true
countUniqueValues++
}
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
case CalcOperatorCountEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].Number || !values[fieldIndex].Number.IsNotEmpty {
countEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
case CalcOperatorCountNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Number && values[fieldIndex].Number.IsNotEmpty {
countNotEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
case CalcOperatorPercentEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].Number || !values[fieldIndex].Number.IsNotEmpty {
countEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Number && values[fieldIndex].Number.IsNotEmpty {
countNotEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentUniqueValues:
countUniqueValues := 0
uniqueValues := map[float64]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Number && values[fieldIndex].Number.IsNotEmpty {
if !uniqueValues[values[fieldIndex].Number.Content] {
uniqueValues[values[fieldIndex].Number.Content] = true
countUniqueValues++
}
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorSum:
sum := 0.0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Number && values[fieldIndex].Number.IsNotEmpty {
sum += values[fieldIndex].Number.Content
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(sum, field.GetNumberFormat())}
case CalcOperatorAverage:
sum := 0.0
count := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Number && values[fieldIndex].Number.IsNotEmpty {
sum += values[fieldIndex].Number.Content
count++
}
}
if 0 != count {
calc.Result = &Value{Number: NewFormattedValueNumber(sum/float64(count), field.GetNumberFormat())}
}
case CalcOperatorMedian:
calcValues := []float64{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Number && values[fieldIndex].Number.IsNotEmpty {
calcValues = append(calcValues, values[fieldIndex].Number.Content)
}
}
sort.Float64s(calcValues)
if len(calcValues) > 0 {
if len(calcValues)%2 == 0 {
calc.Result = &Value{Number: NewFormattedValueNumber((calcValues[len(calcValues)/2-1]+calcValues[len(calcValues)/2])/2, field.GetNumberFormat())}
} else {
calc.Result = &Value{Number: NewFormattedValueNumber(calcValues[len(calcValues)/2], field.GetNumberFormat())}
}
}
case CalcOperatorMin:
minVal := math.MaxFloat64
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Number && values[fieldIndex].Number.IsNotEmpty {
if values[fieldIndex].Number.Content < minVal {
minVal = values[fieldIndex].Number.Content
}
}
}
if math.MaxFloat64 != minVal {
calc.Result = &Value{Number: NewFormattedValueNumber(minVal, field.GetNumberFormat())}
}
case CalcOperatorMax:
maxVal := -math.MaxFloat64
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Number && values[fieldIndex].Number.IsNotEmpty {
if values[fieldIndex].Number.Content > maxVal {
maxVal = values[fieldIndex].Number.Content
}
}
}
if -math.MaxFloat64 != maxVal {
calc.Result = &Value{Number: NewFormattedValueNumber(maxVal, field.GetNumberFormat())}
}
case CalcOperatorRange:
minVal := math.MaxFloat64
maxVal := -math.MaxFloat64
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Number && values[fieldIndex].Number.IsNotEmpty {
if values[fieldIndex].Number.Content < minVal {
minVal = values[fieldIndex].Number.Content
}
if values[fieldIndex].Number.Content > maxVal {
maxVal = values[fieldIndex].Number.Content
}
}
}
if math.MaxFloat64 != minVal && -math.MaxFloat64 != maxVal {
calc.Result = &Value{Number: NewFormattedValueNumber(maxVal-minVal, field.GetNumberFormat())}
}
}
}
func calcFieldText(collection Collection, field Field, fieldIndex int) {
calc := field.GetCalc()
switch calc.Operator {
case CalcOperatorCountAll:
calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
case CalcOperatorCountValues:
countValues := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Text && "" != values[fieldIndex].Text.Content {
countValues++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
case CalcOperatorCountUniqueValues:
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Text && "" != values[fieldIndex].Text.Content {
if !uniqueValues[values[fieldIndex].Text.Content] {
uniqueValues[values[fieldIndex].Text.Content] = true
countUniqueValues++
}
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
case CalcOperatorCountEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].Text || "" == values[fieldIndex].Text.Content {
countEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
case CalcOperatorCountNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Text && "" != values[fieldIndex].Text.Content {
countNotEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
case CalcOperatorPercentEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].Text || "" == values[fieldIndex].Text.Content {
countEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Text && "" != values[fieldIndex].Text.Content {
countNotEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentUniqueValues:
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Text && "" != values[fieldIndex].Text.Content {
if !uniqueValues[values[fieldIndex].Text.Content] {
uniqueValues[values[fieldIndex].Text.Content] = true
countUniqueValues++
}
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
}
}
func calcFieldURL(collection Collection, field Field, fieldIndex int) {
calc := field.GetCalc()
switch calc.Operator {
case CalcOperatorCountAll:
calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
case CalcOperatorCountValues:
countValues := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].URL && "" != values[fieldIndex].URL.Content {
countValues++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
case CalcOperatorCountUniqueValues:
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].URL && "" != values[fieldIndex].URL.Content {
if !uniqueValues[values[fieldIndex].URL.Content] {
uniqueValues[values[fieldIndex].URL.Content] = true
countUniqueValues++
}
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
case CalcOperatorCountEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].URL || "" == values[fieldIndex].URL.Content {
countEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
case CalcOperatorCountNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].URL && "" != values[fieldIndex].URL.Content {
countNotEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
case CalcOperatorPercentEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].URL || "" == values[fieldIndex].URL.Content {
countEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].URL && "" != values[fieldIndex].URL.Content {
countNotEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentUniqueValues:
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].URL && "" != values[fieldIndex].URL.Content {
if !uniqueValues[values[fieldIndex].URL.Content] {
uniqueValues[values[fieldIndex].URL.Content] = true
countUniqueValues++
}
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
}
}
func calcFieldEmail(collection Collection, field Field, fieldIndex int) {
calc := field.GetCalc()
switch calc.Operator {
case CalcOperatorCountAll:
calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
case CalcOperatorCountValues:
countValues := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Email && "" != values[fieldIndex].Email.Content {
countValues++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
case CalcOperatorCountUniqueValues:
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Email && "" != values[fieldIndex].Email.Content {
if !uniqueValues[values[fieldIndex].Email.Content] {
uniqueValues[values[fieldIndex].Email.Content] = true
countUniqueValues++
}
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
case CalcOperatorCountEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].Email || "" == values[fieldIndex].Email.Content {
countEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
case CalcOperatorCountNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Email && "" != values[fieldIndex].Email.Content {
countNotEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
case CalcOperatorPercentEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].Email || "" == values[fieldIndex].Email.Content {
countEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Email && "" != values[fieldIndex].Email.Content {
countNotEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentUniqueValues:
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Email && "" != values[fieldIndex].Email.Content {
if !uniqueValues[values[fieldIndex].Email.Content] {
uniqueValues[values[fieldIndex].Email.Content] = true
countUniqueValues++
}
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
}
}
func calcFieldPhone(collection Collection, field Field, fieldIndex int) {
calc := field.GetCalc()
switch calc.Operator {
case CalcOperatorCountAll:
calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
case CalcOperatorCountValues:
countValues := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Phone && "" != values[fieldIndex].Phone.Content {
countValues++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
case CalcOperatorCountUniqueValues:
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Phone && "" != values[fieldIndex].Phone.Content {
if !uniqueValues[values[fieldIndex].Phone.Content] {
uniqueValues[values[fieldIndex].Phone.Content] = true
countUniqueValues++
}
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
case CalcOperatorCountEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].Phone || "" == values[fieldIndex].Phone.Content {
countEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
case CalcOperatorCountNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Phone && "" != values[fieldIndex].Phone.Content {
countNotEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
case CalcOperatorPercentEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].Phone || "" == values[fieldIndex].Phone.Content {
countEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Phone && "" != values[fieldIndex].Phone.Content {
countNotEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentUniqueValues:
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Phone && "" != values[fieldIndex].Phone.Content {
if !uniqueValues[values[fieldIndex].Phone.Content] {
uniqueValues[values[fieldIndex].Phone.Content] = true
countUniqueValues++
}
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
}
}
func calcFieldBlock(collection Collection, field Field, fieldIndex int) {
calc := field.GetCalc()
switch calc.Operator {
case CalcOperatorCountAll:
calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
case CalcOperatorCountValues:
countValues := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Block && "" != values[fieldIndex].Block.Content {
countValues++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
case CalcOperatorCountUniqueValues:
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Block && "" != values[fieldIndex].Block.Content {
if !uniqueValues[values[fieldIndex].Block.Content] {
uniqueValues[values[fieldIndex].Block.Content] = true
countUniqueValues++
}
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
case CalcOperatorCountEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].Block || "" == values[fieldIndex].Block.Content {
countEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
case CalcOperatorCountNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Block && "" != values[fieldIndex].Block.Content {
countNotEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
case CalcOperatorPercentEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].Block || "" == values[fieldIndex].Block.Content {
countEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Block && "" != values[fieldIndex].Block.Content {
countNotEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentUniqueValues:
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Block && "" != values[fieldIndex].Block.Content {
if !uniqueValues[values[fieldIndex].Block.Content] {
uniqueValues[values[fieldIndex].Block.Content] = true
countUniqueValues++
}
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
}
}
func calcFieldCreated(collection Collection, field Field, fieldIndex int) {
calc := field.GetCalc()
switch calc.Operator {
case CalcOperatorCountAll:
calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
case CalcOperatorCountValues:
countValues := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Created {
countValues++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
case CalcOperatorCountUniqueValues:
countUniqueValues := 0
uniqueValues := map[int64]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Created {
if _, ok := uniqueValues[values[fieldIndex].Created.Content]; !ok {
countUniqueValues++
uniqueValues[values[fieldIndex].Created.Content] = true
}
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
case CalcOperatorCountEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].Created {
countEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
case CalcOperatorCountNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Created {
countNotEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
case CalcOperatorPercentEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].Created {
countEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Created {
countNotEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentUniqueValues:
countUniqueValues := 0
uniqueValues := map[int64]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Created {
if _, ok := uniqueValues[values[fieldIndex].Created.Content]; !ok {
countUniqueValues++
uniqueValues[values[fieldIndex].Created.Content] = true
}
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorEarliest:
earliest := int64(0)
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Created {
if 0 == earliest || earliest > values[fieldIndex].Created.Content {
earliest = values[fieldIndex].Created.Content
}
}
}
if 0 != earliest {
calc.Result = &Value{Created: NewFormattedValueCreated(earliest, 0, CreatedFormatNone)}
}
case CalcOperatorLatest:
latest := int64(0)
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Created {
if 0 == latest || latest < values[fieldIndex].Created.Content {
latest = values[fieldIndex].Created.Content
}
}
}
if 0 != latest {
calc.Result = &Value{Created: NewFormattedValueCreated(latest, 0, CreatedFormatNone)}
}
case CalcOperatorRange:
earliest := int64(0)
latest := int64(0)
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Created {
if 0 == earliest || earliest > values[fieldIndex].Created.Content {
earliest = values[fieldIndex].Created.Content
}
if 0 == latest || latest < values[fieldIndex].Created.Content {
latest = values[fieldIndex].Created.Content
}
}
}
if 0 != earliest && 0 != latest {
calc.Result = &Value{Created: NewFormattedValueCreated(earliest, latest, CreatedFormatDuration)}
}
}
}
func calcFieldUpdated(collection Collection, field Field, fieldIndex int) {
calc := field.GetCalc()
switch calc.Operator {
case CalcOperatorCountAll:
calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
case CalcOperatorCountValues:
countValues := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Updated && values[fieldIndex].Updated.IsNotEmpty {
countValues++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
case CalcOperatorCountUniqueValues:
countUniqueValues := 0
uniqueValues := map[int64]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Updated && values[fieldIndex].Updated.IsNotEmpty {
if _, ok := uniqueValues[values[fieldIndex].Updated.Content]; !ok {
countUniqueValues++
uniqueValues[values[fieldIndex].Updated.Content] = true
}
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
case CalcOperatorCountEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].Updated || !values[fieldIndex].Updated.IsNotEmpty {
countEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
case CalcOperatorCountNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Updated && values[fieldIndex].Updated.IsNotEmpty {
countNotEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
case CalcOperatorPercentEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].Updated || !values[fieldIndex].Updated.IsNotEmpty {
countEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Updated && values[fieldIndex].Updated.IsNotEmpty {
countNotEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentUniqueValues:
countUniqueValues := 0
uniqueValues := map[int64]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Updated && values[fieldIndex].Updated.IsNotEmpty {
if _, ok := uniqueValues[values[fieldIndex].Updated.Content]; !ok {
countUniqueValues++
uniqueValues[values[fieldIndex].Updated.Content] = true
}
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorEarliest:
earliest := int64(0)
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Updated && values[fieldIndex].Updated.IsNotEmpty {
if 0 == earliest || earliest > values[fieldIndex].Updated.Content {
earliest = values[fieldIndex].Updated.Content
}
}
}
if 0 != earliest {
calc.Result = &Value{Updated: NewFormattedValueUpdated(earliest, 0, UpdatedFormatNone)}
}
case CalcOperatorLatest:
latest := int64(0)
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Updated && values[fieldIndex].Updated.IsNotEmpty {
if 0 == latest || latest < values[fieldIndex].Updated.Content {
latest = values[fieldIndex].Updated.Content
}
}
}
if 0 != latest {
calc.Result = &Value{Updated: NewFormattedValueUpdated(latest, 0, UpdatedFormatNone)}
}
case CalcOperatorRange:
earliest := int64(0)
latest := int64(0)
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Updated && values[fieldIndex].Updated.IsNotEmpty {
if 0 == earliest || earliest > values[fieldIndex].Updated.Content {
earliest = values[fieldIndex].Updated.Content
}
if 0 == latest || latest < values[fieldIndex].Updated.Content {
latest = values[fieldIndex].Updated.Content
}
}
}
if 0 != earliest && 0 != latest {
calc.Result = &Value{Updated: NewFormattedValueUpdated(earliest, latest, UpdatedFormatDuration)}
}
}
}
func calcFieldCheckbox(collection Collection, field Field, fieldIndex int) {
calc := field.GetCalc()
switch calc.Operator {
case CalcOperatorCountAll:
calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
case CalcOperatorChecked:
countChecked := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Checkbox && values[fieldIndex].Checkbox.Checked {
countChecked++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countChecked), NumberFormatNone)}
case CalcOperatorUnchecked:
countUnchecked := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Checkbox && !values[fieldIndex].Checkbox.Checked {
countUnchecked++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUnchecked), NumberFormatNone)}
case CalcOperatorPercentChecked:
countChecked := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Checkbox && values[fieldIndex].Checkbox.Checked {
countChecked++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countChecked)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentUnchecked:
countUnchecked := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Checkbox && !values[fieldIndex].Checkbox.Checked {
countUnchecked++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUnchecked)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
}
}
func calcFieldRelation(collection Collection, field Field, fieldIndex int) {
calc := field.GetCalc()
switch calc.Operator {
case CalcOperatorCountAll:
calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
case CalcOperatorCountValues:
countValues := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Relation {
countValues++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
case CalcOperatorCountUniqueValues:
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Relation {
for _, id := range values[fieldIndex].Relation.BlockIDs {
if !uniqueValues[id] {
uniqueValues[id] = true
countUniqueValues++
}
}
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
case CalcOperatorCountEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].Relation || 0 == len(values[fieldIndex].Relation.BlockIDs) {
countEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
case CalcOperatorCountNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Relation && 0 < len(values[fieldIndex].Relation.BlockIDs) {
countNotEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
case CalcOperatorPercentEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].Relation || 0 == len(values[fieldIndex].Relation.BlockIDs) {
countEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Relation && 0 < len(values[fieldIndex].Relation.BlockIDs) {
countNotEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentUniqueValues:
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Relation {
for _, id := range values[fieldIndex].Relation.BlockIDs {
if !uniqueValues[id] {
uniqueValues[id] = true
countUniqueValues++
}
}
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
}
}
func calcFieldRollup(collection Collection, field Field, fieldIndex int) {
calc := field.GetCalc()
switch calc.Operator {
case CalcOperatorCountAll:
calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(collection.GetItems())), NumberFormatNone)}
case CalcOperatorCountValues:
countValues := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Rollup {
countValues++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
case CalcOperatorCountUniqueValues:
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Rollup {
for _, content := range values[fieldIndex].Rollup.Contents {
switch content.Type {
case KeyTypeRelation:
for _, relationVal := range content.Relation.Contents {
key := relationVal.String(true)
if !uniqueValues[key] {
uniqueValues[key] = true
countUniqueValues++
}
}
case KeyTypeMSelect:
for _, mSelectVal := range content.MSelect {
if !uniqueValues[mSelectVal.Content] {
uniqueValues[mSelectVal.Content] = true
countUniqueValues++
}
}
case KeyTypeMAsset:
for _, mAssetVal := range content.MAsset {
if !uniqueValues[mAssetVal.Content] {
uniqueValues[mAssetVal.Content] = true
countUniqueValues++
}
}
default:
key := content.String(true)
if !uniqueValues[key] {
uniqueValues[key] = true
countUniqueValues++
}
}
}
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
case CalcOperatorCountEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].Rollup || 0 == len(values[fieldIndex].Rollup.Contents) {
countEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
case CalcOperatorCountNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Rollup && 0 < len(values[fieldIndex].Rollup.Contents) {
countNotEmpty++
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
case CalcOperatorPercentEmpty:
countEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil == values[fieldIndex] || nil == values[fieldIndex].Rollup || 0 == len(values[fieldIndex].Rollup.Contents) {
countEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentNotEmpty:
countNotEmpty := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Rollup && 0 < len(values[fieldIndex].Rollup.Contents) {
countNotEmpty++
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorPercentUniqueValues:
countUniqueValues := 0
uniqueValues := map[string]bool{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Rollup {
for _, content := range values[fieldIndex].Rollup.Contents {
if !uniqueValues[content.String(true)] {
uniqueValues[content.String(true)] = true
countUniqueValues++
}
}
}
}
if 0 < len(collection.GetItems()) {
calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues)/float64(len(collection.GetItems())), NumberFormatPercent)}
}
case CalcOperatorSum:
sum := 0.0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Rollup && 0 < len(values[fieldIndex].Rollup.Contents) {
for _, content := range values[fieldIndex].Rollup.Contents {
val, _ := util.Convert2Float(content.String(false))
sum += val
}
}
}
calc.Result = &Value{Number: NewFormattedValueNumber(sum, field.GetNumberFormat())}
case CalcOperatorAverage:
sum := 0.0
count := 0
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Rollup && 0 < len(values[fieldIndex].Rollup.Contents) {
for _, content := range values[fieldIndex].Rollup.Contents {
val, _ := util.Convert2Float(content.String(false))
sum += val
count++
}
}
}
if 0 != count {
calc.Result = &Value{Number: NewFormattedValueNumber(sum/float64(count), field.GetNumberFormat())}
}
case CalcOperatorMedian:
calcValues := []float64{}
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Rollup && 0 < len(values[fieldIndex].Rollup.Contents) {
for _, content := range values[fieldIndex].Rollup.Contents {
val, _ := util.Convert2Float(content.String(false))
calcValues = append(calcValues, val)
}
}
}
sort.Float64s(calcValues)
if 0 < len(calcValues) {
if 0 == len(calcValues)%2 {
calc.Result = &Value{Number: NewFormattedValueNumber((calcValues[len(calcValues)/2-1]+calcValues[len(calcValues)/2])/2, field.GetNumberFormat())}
} else {
calc.Result = &Value{Number: NewFormattedValueNumber(calcValues[len(calcValues)/2], field.GetNumberFormat())}
}
}
case CalcOperatorMin:
minVal := math.MaxFloat64
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Rollup && 0 < len(values[fieldIndex].Rollup.Contents) {
for _, content := range values[fieldIndex].Rollup.Contents {
val, _ := util.Convert2Float(content.String(false))
if val < minVal {
minVal = val
}
}
}
}
if math.MaxFloat64 != minVal {
calc.Result = &Value{Number: NewFormattedValueNumber(minVal, field.GetNumberFormat())}
}
case CalcOperatorMax:
maxVal := -math.MaxFloat64
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Rollup && 0 < len(values[fieldIndex].Rollup.Contents) {
for _, content := range values[fieldIndex].Rollup.Contents {
val, _ := util.Convert2Float(content.String(false))
if val > maxVal {
maxVal = val
}
}
}
}
if -math.MaxFloat64 != maxVal {
calc.Result = &Value{Number: NewFormattedValueNumber(maxVal, field.GetNumberFormat())}
}
case CalcOperatorRange:
minVal := math.MaxFloat64
maxVal := -math.MaxFloat64
for _, item := range collection.GetItems() {
values := item.GetValues()
if nil != values[fieldIndex] && nil != values[fieldIndex].Rollup && 0 < len(values[fieldIndex].Rollup.Contents) {
for _, content := range values[fieldIndex].Rollup.Contents {
val, _ := util.Convert2Float(content.String(false))
if val < minVal {
minVal = val
}
if val > maxVal {
maxVal = val
}
}
}
}
if math.MaxFloat64 != minVal && -math.MaxFloat64 != maxVal {
calc.Result = &Value{Number: NewFormattedValueNumber(maxVal-minVal, field.GetNumberFormat())}
}
}
}