From f75d5e50b4b949dfbff8b8862693e984ee5edc32 Mon Sep 17 00:00:00 2001
From: Daniel <845765@qq.com>
Date: Wed, 15 May 2024 00:30:08 +0800
Subject: [PATCH] :recycle: Improve av structure
---
kernel/av/calc.go | 51 ++
kernel/av/table.go | 1460 ---------------------------------------
kernel/av/table_calc.go | 1446 ++++++++++++++++++++++++++++++++++++++
3 files changed, 1497 insertions(+), 1460 deletions(-)
create mode 100644 kernel/av/calc.go
create mode 100644 kernel/av/table_calc.go
diff --git a/kernel/av/calc.go b/kernel/av/calc.go
new file mode 100644
index 000000000..4260fcdda
--- /dev/null
+++ b/kernel/av/calc.go
@@ -0,0 +1,51 @@
+// 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 .
+
+package av
+
+type Calculable interface {
+ CalcCols()
+}
+
+type ColumnCalc struct {
+ Operator CalcOperator `json:"operator"`
+ Result *Value `json:"result"`
+}
+
+type CalcOperator string
+
+const (
+ CalcOperatorNone CalcOperator = ""
+ 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"
+ 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"
+)
diff --git a/kernel/av/table.go b/kernel/av/table.go
index 850f86850..3818121aa 100644
--- a/kernel/av/table.go
+++ b/kernel/av/table.go
@@ -17,10 +17,7 @@
package av
import (
- "math"
"sort"
-
- "github.com/siyuan-note/siyuan/kernel/util"
)
// LayoutTable 描述了表格布局的结构。
@@ -45,40 +42,6 @@ type ViewTableColumn struct {
Calc *ColumnCalc `json:"calc,omitempty"` // 计算
}
-type Calculable interface {
- CalcCols()
-}
-
-type ColumnCalc struct {
- Operator CalcOperator `json:"operator"`
- Result *Value `json:"result"`
-}
-
-type CalcOperator string
-
-const (
- CalcOperatorNone CalcOperator = ""
- 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"
- 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"
-)
-
// Table 描述了表格实例的结构。
type Table struct {
ID string `json:"id"` // 表格布局 ID
@@ -314,1426 +277,3 @@ func (table *Table) FilterRows(attrView *AttributeView) {
}
table.Rows = rows
}
-
-func (table *Table) CalcCols() {
- for i, col := range table.Columns {
- if nil == col.Calc {
- continue
- }
-
- if CalcOperatorNone == col.Calc.Operator {
- continue
- }
-
- switch col.Type {
- case KeyTypeBlock:
- table.calcColBlock(col, i)
- case KeyTypeText:
- table.calcColText(col, i)
- case KeyTypeNumber:
- table.calcColNumber(col, i)
- case KeyTypeDate:
- table.calcColDate(col, i)
- case KeyTypeSelect:
- table.calcColSelect(col, i)
- case KeyTypeMSelect:
- table.calcColMSelect(col, i)
- case KeyTypeURL:
- table.calcColURL(col, i)
- case KeyTypeEmail:
- table.calcColEmail(col, i)
- case KeyTypePhone:
- table.calcColPhone(col, i)
- case KeyTypeMAsset:
- table.calcColMAsset(col, i)
- case KeyTypeTemplate:
- table.calcColTemplate(col, i)
- case KeyTypeCreated:
- table.calcColCreated(col, i)
- case KeyTypeUpdated:
- table.calcColUpdated(col, i)
- case KeyTypeCheckbox:
- table.calcColCheckbox(col, i)
- case KeyTypeRelation:
- table.calcColRelation(col, i)
- case KeyTypeRollup:
- table.calcColRollup(col, i)
- }
- }
-}
-
-func (table *Table) calcColTemplate(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
- if !uniqueValues[row.Cells[colIndex].Value.Template.Content] {
- uniqueValues[row.Cells[colIndex].Value.Template.Content] = true
- countUniqueValues++
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Template || "" == row.Cells[colIndex].Value.Template.Content {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Template || "" == row.Cells[colIndex].Value.Template.Content {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorSum:
- sum := 0.0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
- val, _ := util.Convert2Float(row.Cells[colIndex].Value.Template.Content)
- sum += val
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(sum, col.NumberFormat)}
- case CalcOperatorAverage:
- sum := 0.0
- count := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
- val, _ := util.Convert2Float(row.Cells[colIndex].Value.Template.Content)
- sum += val
- count++
- }
- }
- if 0 != count {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(sum/float64(count), col.NumberFormat)}
- }
- case CalcOperatorMedian:
- values := []float64{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
- val, _ := util.Convert2Float(row.Cells[colIndex].Value.Template.Content)
- values = append(values, val)
- }
- }
- sort.Float64s(values)
- if len(values) > 0 {
- if len(values)%2 == 0 {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber((values[len(values)/2-1]+values[len(values)/2])/2, col.NumberFormat)}
- } else {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(values[len(values)/2], col.NumberFormat)}
- }
- }
- case CalcOperatorMin:
- minVal := math.MaxFloat64
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
- val, _ := util.Convert2Float(row.Cells[colIndex].Value.Template.Content)
- if val < minVal {
- minVal = val
- }
- }
- }
- if math.MaxFloat64 != minVal {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(minVal, col.NumberFormat)}
- }
- case CalcOperatorMax:
- maxVal := -math.MaxFloat64
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
- val, _ := util.Convert2Float(row.Cells[colIndex].Value.Template.Content)
- if val > maxVal {
- maxVal = val
- }
- }
- }
- if -math.MaxFloat64 != maxVal {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(maxVal, col.NumberFormat)}
- }
- case CalcOperatorRange:
- minVal := math.MaxFloat64
- maxVal := -math.MaxFloat64
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
- val, _ := util.Convert2Float(row.Cells[colIndex].Value.Template.Content)
- if val < minVal {
- minVal = val
- }
- if val > maxVal {
- maxVal = val
- }
- }
- }
- if math.MaxFloat64 != minVal && -math.MaxFloat64 != maxVal {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(maxVal-minVal, col.NumberFormat)}
- }
- }
-}
-
-func (table *Table) calcColMAsset(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MAsset && 0 < len(row.Cells[colIndex].Value.MAsset) {
- countValues += len(row.Cells[colIndex].Value.MAsset)
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MAsset && 0 < len(row.Cells[colIndex].Value.MAsset) {
- for _, sel := range row.Cells[colIndex].Value.MAsset {
- if _, ok := uniqueValues[sel.Content]; !ok {
- uniqueValues[sel.Content] = true
- countUniqueValues++
- }
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.MAsset || 0 == len(row.Cells[colIndex].Value.MAsset) {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MAsset && 0 < len(row.Cells[colIndex].Value.MAsset) {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.MAsset || 0 == len(row.Cells[colIndex].Value.MAsset) {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MAsset && 0 < len(row.Cells[colIndex].Value.MAsset) {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- }
-}
-
-func (table *Table) calcColMSelect(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) {
- countValues += len(row.Cells[colIndex].Value.MSelect)
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) {
- for _, sel := range row.Cells[colIndex].Value.MSelect {
- if _, ok := uniqueValues[sel.Content]; !ok {
- uniqueValues[sel.Content] = true
- countUniqueValues++
- }
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.MSelect || 0 == len(row.Cells[colIndex].Value.MSelect) {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.MSelect || 0 == len(row.Cells[colIndex].Value.MSelect) {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- }
-}
-
-func (table *Table) calcColSelect(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) && nil != row.Cells[colIndex].Value.MSelect[0] && "" != row.Cells[colIndex].Value.MSelect[0].Content {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) && nil != row.Cells[colIndex].Value.MSelect[0] && "" != row.Cells[colIndex].Value.MSelect[0].Content {
- if _, ok := uniqueValues[row.Cells[colIndex].Value.MSelect[0].Content]; !ok {
- uniqueValues[row.Cells[colIndex].Value.MSelect[0].Content] = true
- countUniqueValues++
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.MSelect || 1 > len(row.Cells[colIndex].Value.MSelect) || nil == row.Cells[colIndex].Value.MSelect[0] || "" == row.Cells[colIndex].Value.MSelect[0].Content {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) && nil != row.Cells[colIndex].Value.MSelect[0] && "" != row.Cells[colIndex].Value.MSelect[0].Content {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.MSelect || 1 > len(row.Cells[colIndex].Value.MSelect) || nil == row.Cells[colIndex].Value.MSelect[0] || "" == row.Cells[colIndex].Value.MSelect[0].Content {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) && nil != row.Cells[colIndex].Value.MSelect[0] && "" != row.Cells[colIndex].Value.MSelect[0].Content {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- }
-}
-
-func (table *Table) calcColDate(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Date && row.Cells[colIndex].Value.Date.IsNotEmpty {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[int64]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Date && row.Cells[colIndex].Value.Date.IsNotEmpty {
- if _, ok := uniqueValues[row.Cells[colIndex].Value.Date.Content]; !ok {
- countUniqueValues++
- uniqueValues[row.Cells[colIndex].Value.Date.Content] = true
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Date || !row.Cells[colIndex].Value.Date.IsNotEmpty {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Date && row.Cells[colIndex].Value.Date.IsNotEmpty {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Date || !row.Cells[colIndex].Value.Date.IsNotEmpty {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Date && row.Cells[colIndex].Value.Date.IsNotEmpty {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorEarliest:
- earliest := int64(0)
- var isNotTime, hasEndDate bool
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Date && row.Cells[colIndex].Value.Date.IsNotEmpty {
- if 0 == earliest || earliest > row.Cells[colIndex].Value.Date.Content {
- earliest = row.Cells[colIndex].Value.Date.Content
- isNotTime = row.Cells[colIndex].Value.Date.IsNotTime
- hasEndDate = row.Cells[colIndex].Value.Date.HasEndDate
- }
- }
- }
- if 0 != earliest {
- col.Calc.Result = &Value{Date: NewFormattedValueDate(earliest, 0, DateFormatNone, isNotTime, hasEndDate)}
- }
- case CalcOperatorLatest:
- latest := int64(0)
- var isNotTime, hasEndDate bool
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Date && row.Cells[colIndex].Value.Date.IsNotEmpty {
- if 0 == latest || latest < row.Cells[colIndex].Value.Date.Content {
- latest = row.Cells[colIndex].Value.Date.Content
- isNotTime = row.Cells[colIndex].Value.Date.IsNotTime
- hasEndDate = row.Cells[colIndex].Value.Date.HasEndDate
- }
- }
- }
- if 0 != latest {
- col.Calc.Result = &Value{Date: NewFormattedValueDate(latest, 0, DateFormatNone, isNotTime, hasEndDate)}
- }
- case CalcOperatorRange:
- earliest := int64(0)
- latest := int64(0)
- var isNotTime, hasEndDate bool
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Date && row.Cells[colIndex].Value.Date.IsNotEmpty {
- if 0 == earliest || earliest > row.Cells[colIndex].Value.Date.Content {
- earliest = row.Cells[colIndex].Value.Date.Content
- isNotTime = row.Cells[colIndex].Value.Date.IsNotTime
- hasEndDate = row.Cells[colIndex].Value.Date.HasEndDate
- }
- if 0 == latest || latest < row.Cells[colIndex].Value.Date.Content {
- latest = row.Cells[colIndex].Value.Date.Content
- isNotTime = row.Cells[colIndex].Value.Date.IsNotTime
- hasEndDate = row.Cells[colIndex].Value.Date.HasEndDate
- }
- }
- }
- if 0 != earliest && 0 != latest {
- col.Calc.Result = &Value{Date: NewFormattedValueDate(earliest, latest, DateFormatDuration, isNotTime, hasEndDate)}
- }
- }
-}
-
-func (table *Table) calcColNumber(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[float64]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
- if !uniqueValues[row.Cells[colIndex].Value.Number.Content] {
- uniqueValues[row.Cells[colIndex].Value.Number.Content] = true
- countUniqueValues++
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Number || !row.Cells[colIndex].Value.Number.IsNotEmpty {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Number || !row.Cells[colIndex].Value.Number.IsNotEmpty {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorSum:
- sum := 0.0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
- sum += row.Cells[colIndex].Value.Number.Content
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(sum, col.NumberFormat)}
- case CalcOperatorAverage:
- sum := 0.0
- count := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
- sum += row.Cells[colIndex].Value.Number.Content
- count++
- }
- }
- if 0 != count {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(sum/float64(count), col.NumberFormat)}
- }
- case CalcOperatorMedian:
- values := []float64{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
- values = append(values, row.Cells[colIndex].Value.Number.Content)
- }
- }
- sort.Float64s(values)
- if len(values) > 0 {
- if len(values)%2 == 0 {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber((values[len(values)/2-1]+values[len(values)/2])/2, col.NumberFormat)}
- } else {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(values[len(values)/2], col.NumberFormat)}
- }
- }
- case CalcOperatorMin:
- minVal := math.MaxFloat64
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
- if row.Cells[colIndex].Value.Number.Content < minVal {
- minVal = row.Cells[colIndex].Value.Number.Content
- }
- }
- }
- if math.MaxFloat64 != minVal {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(minVal, col.NumberFormat)}
- }
- case CalcOperatorMax:
- maxVal := -math.MaxFloat64
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
- if row.Cells[colIndex].Value.Number.Content > maxVal {
- maxVal = row.Cells[colIndex].Value.Number.Content
- }
- }
- }
- if -math.MaxFloat64 != maxVal {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(maxVal, col.NumberFormat)}
- }
- case CalcOperatorRange:
- minVal := math.MaxFloat64
- maxVal := -math.MaxFloat64
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
- if row.Cells[colIndex].Value.Number.Content < minVal {
- minVal = row.Cells[colIndex].Value.Number.Content
- }
- if row.Cells[colIndex].Value.Number.Content > maxVal {
- maxVal = row.Cells[colIndex].Value.Number.Content
- }
- }
- }
- if math.MaxFloat64 != minVal && -math.MaxFloat64 != maxVal {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(maxVal-minVal, col.NumberFormat)}
- }
- }
-}
-
-func (table *Table) calcColText(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Text && "" != row.Cells[colIndex].Value.Text.Content {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Text && "" != row.Cells[colIndex].Value.Text.Content {
- if !uniqueValues[row.Cells[colIndex].Value.Text.Content] {
- uniqueValues[row.Cells[colIndex].Value.Text.Content] = true
- countUniqueValues++
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Text || "" == row.Cells[colIndex].Value.Text.Content {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Text && "" != row.Cells[colIndex].Value.Text.Content {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Text || "" == row.Cells[colIndex].Value.Text.Content {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Text && "" != row.Cells[colIndex].Value.Text.Content {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- }
-}
-
-func (table *Table) calcColURL(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.URL && "" != row.Cells[colIndex].Value.URL.Content {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.URL && "" != row.Cells[colIndex].Value.URL.Content {
- if !uniqueValues[row.Cells[colIndex].Value.URL.Content] {
- uniqueValues[row.Cells[colIndex].Value.URL.Content] = true
- countUniqueValues++
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.URL || "" == row.Cells[colIndex].Value.URL.Content {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.URL && "" != row.Cells[colIndex].Value.URL.Content {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.URL || "" == row.Cells[colIndex].Value.URL.Content {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.URL && "" != row.Cells[colIndex].Value.URL.Content {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- }
-}
-
-func (table *Table) calcColEmail(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Email && "" != row.Cells[colIndex].Value.Email.Content {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Email && "" != row.Cells[colIndex].Value.Email.Content {
- if !uniqueValues[row.Cells[colIndex].Value.Email.Content] {
- uniqueValues[row.Cells[colIndex].Value.Email.Content] = true
- countUniqueValues++
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Email || "" == row.Cells[colIndex].Value.Email.Content {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Email && "" != row.Cells[colIndex].Value.Email.Content {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Email || "" == row.Cells[colIndex].Value.Email.Content {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Email && "" != row.Cells[colIndex].Value.Email.Content {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- }
-}
-
-func (table *Table) calcColPhone(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Phone && "" != row.Cells[colIndex].Value.Phone.Content {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Phone && "" != row.Cells[colIndex].Value.Phone.Content {
- if !uniqueValues[row.Cells[colIndex].Value.Phone.Content] {
- uniqueValues[row.Cells[colIndex].Value.Phone.Content] = true
- countUniqueValues++
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Phone || "" == row.Cells[colIndex].Value.Phone.Content {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Phone && "" != row.Cells[colIndex].Value.Phone.Content {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Phone || "" == row.Cells[colIndex].Value.Phone.Content {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Phone && "" != row.Cells[colIndex].Value.Phone.Content {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- }
-}
-
-func (table *Table) calcColBlock(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Block && "" != row.Cells[colIndex].Value.Block.Content {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Block && "" != row.Cells[colIndex].Value.Block.Content {
- if !uniqueValues[row.Cells[colIndex].Value.Block.Content] {
- uniqueValues[row.Cells[colIndex].Value.Block.Content] = true
- countUniqueValues++
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Block || "" == row.Cells[colIndex].Value.Block.Content {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Block && "" != row.Cells[colIndex].Value.Block.Content {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Block || "" == row.Cells[colIndex].Value.Block.Content {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Block && "" != row.Cells[colIndex].Value.Block.Content {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- }
-}
-
-func (table *Table) calcColCreated(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Created {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[int64]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Created {
- if _, ok := uniqueValues[row.Cells[colIndex].Value.Created.Content]; !ok {
- countUniqueValues++
- uniqueValues[row.Cells[colIndex].Value.Created.Content] = true
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Created {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Created {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Created {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Created {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorEarliest:
- earliest := int64(0)
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Created {
- if 0 == earliest || earliest > row.Cells[colIndex].Value.Created.Content {
- earliest = row.Cells[colIndex].Value.Created.Content
- }
- }
- }
- if 0 != earliest {
- col.Calc.Result = &Value{Created: NewFormattedValueCreated(earliest, 0, CreatedFormatNone)}
- }
- case CalcOperatorLatest:
- latest := int64(0)
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Created {
- if 0 == latest || latest < row.Cells[colIndex].Value.Created.Content {
- latest = row.Cells[colIndex].Value.Created.Content
- }
- }
- }
- if 0 != latest {
- col.Calc.Result = &Value{Created: NewFormattedValueCreated(latest, 0, CreatedFormatNone)}
- }
- case CalcOperatorRange:
- earliest := int64(0)
- latest := int64(0)
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Created {
- if 0 == earliest || earliest > row.Cells[colIndex].Value.Created.Content {
- earliest = row.Cells[colIndex].Value.Created.Content
- }
- if 0 == latest || latest < row.Cells[colIndex].Value.Created.Content {
- latest = row.Cells[colIndex].Value.Created.Content
- }
- }
- }
- if 0 != earliest && 0 != latest {
- col.Calc.Result = &Value{Created: NewFormattedValueCreated(earliest, latest, CreatedFormatDuration)}
- }
- }
-}
-
-func (table *Table) calcColUpdated(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Updated && row.Cells[colIndex].Value.Updated.IsNotEmpty {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[int64]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Updated && row.Cells[colIndex].Value.Updated.IsNotEmpty {
- if _, ok := uniqueValues[row.Cells[colIndex].Value.Updated.Content]; !ok {
- countUniqueValues++
- uniqueValues[row.Cells[colIndex].Value.Updated.Content] = true
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Updated || !row.Cells[colIndex].Value.Updated.IsNotEmpty {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Updated && row.Cells[colIndex].Value.Updated.IsNotEmpty {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Updated || !row.Cells[colIndex].Value.Updated.IsNotEmpty {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Updated && row.Cells[colIndex].Value.Updated.IsNotEmpty {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorEarliest:
- earliest := int64(0)
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Updated && row.Cells[colIndex].Value.Updated.IsNotEmpty {
- if 0 == earliest || earliest > row.Cells[colIndex].Value.Updated.Content {
- earliest = row.Cells[colIndex].Value.Updated.Content
- }
- }
- }
- if 0 != earliest {
- col.Calc.Result = &Value{Updated: NewFormattedValueUpdated(earliest, 0, UpdatedFormatNone)}
- }
- case CalcOperatorLatest:
- latest := int64(0)
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Updated && row.Cells[colIndex].Value.Updated.IsNotEmpty {
- if 0 == latest || latest < row.Cells[colIndex].Value.Updated.Content {
- latest = row.Cells[colIndex].Value.Updated.Content
- }
- }
- }
- if 0 != latest {
- col.Calc.Result = &Value{Updated: NewFormattedValueUpdated(latest, 0, UpdatedFormatNone)}
- }
- case CalcOperatorRange:
- earliest := int64(0)
- latest := int64(0)
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Updated && row.Cells[colIndex].Value.Updated.IsNotEmpty {
- if 0 == earliest || earliest > row.Cells[colIndex].Value.Updated.Content {
- earliest = row.Cells[colIndex].Value.Updated.Content
- }
- if 0 == latest || latest < row.Cells[colIndex].Value.Updated.Content {
- latest = row.Cells[colIndex].Value.Updated.Content
- }
- }
- }
- if 0 != earliest && 0 != latest {
- col.Calc.Result = &Value{Updated: NewFormattedValueUpdated(earliest, latest, UpdatedFormatDuration)}
- }
- }
-}
-
-func (table *Table) calcColCheckbox(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorChecked:
- countChecked := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Checkbox && row.Cells[colIndex].Value.Checkbox.Checked {
- countChecked++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countChecked), NumberFormatNone)}
- case CalcOperatorUnchecked:
- countUnchecked := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Checkbox && !row.Cells[colIndex].Value.Checkbox.Checked {
- countUnchecked++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUnchecked), NumberFormatNone)}
- case CalcOperatorPercentChecked:
- countChecked := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Checkbox && row.Cells[colIndex].Value.Checkbox.Checked {
- countChecked++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countChecked)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentUnchecked:
- countUnchecked := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Checkbox && !row.Cells[colIndex].Value.Checkbox.Checked {
- countUnchecked++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUnchecked)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- }
-}
-
-func (table *Table) calcColRelation(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Relation {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Relation {
- for _, id := range row.Cells[colIndex].Value.Relation.BlockIDs {
- if !uniqueValues[id] {
- uniqueValues[id] = true
- countUniqueValues++
- }
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Relation || 0 == len(row.Cells[colIndex].Value.Relation.BlockIDs) {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Relation && 0 < len(row.Cells[colIndex].Value.Relation.BlockIDs) {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Relation || 0 == len(row.Cells[colIndex].Value.Relation.BlockIDs) {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Relation && 0 < len(row.Cells[colIndex].Value.Relation.BlockIDs) {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- }
-}
-
-func (table *Table) calcColRollup(col *TableColumn, colIndex int) {
- switch col.Calc.Operator {
- case CalcOperatorCountAll:
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
- case CalcOperatorCountValues:
- countValues := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup {
- countValues++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
- case CalcOperatorCountUniqueValues:
- countUniqueValues := 0
- uniqueValues := map[string]bool{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup {
- for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
- if !uniqueValues[content.String(true)] {
- uniqueValues[content.String(true)] = true
- countUniqueValues++
- }
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
- case CalcOperatorCountEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Rollup || 0 == len(row.Cells[colIndex].Value.Rollup.Contents) {
- countEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
- case CalcOperatorCountNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
- countNotEmpty++
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
- case CalcOperatorPercentEmpty:
- countEmpty := 0
- for _, row := range table.Rows {
- if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Rollup || 0 == len(row.Cells[colIndex].Value.Rollup.Contents) {
- countEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorPercentNotEmpty:
- countNotEmpty := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
- countNotEmpty++
- }
- }
- if 0 < len(table.Rows) {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
- }
- case CalcOperatorSum:
- sum := 0.0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
- for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
- val, _ := util.Convert2Float(content.String(false))
- sum += val
- }
- }
- }
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(sum, col.NumberFormat)}
- case CalcOperatorAverage:
- sum := 0.0
- count := 0
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
- for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
- val, _ := util.Convert2Float(content.String(false))
- sum += val
- count++
- }
- }
- }
- if 0 != count {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(sum/float64(count), col.NumberFormat)}
- }
- case CalcOperatorMedian:
- values := []float64{}
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
- for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
- val, _ := util.Convert2Float(content.String(false))
- values = append(values, val)
- }
- }
- }
- sort.Float64s(values)
- if 0 < len(values) {
- if 0 == len(values)%2 {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber((values[len(values)/2-1]+values[len(values)/2])/2, col.NumberFormat)}
- } else {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(values[len(values)/2], col.NumberFormat)}
- }
- }
- case CalcOperatorMin:
- minVal := math.MaxFloat64
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
- for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
- val, _ := util.Convert2Float(content.String(false))
- if val < minVal {
- minVal = val
- }
- }
- }
- }
- if math.MaxFloat64 != minVal {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(minVal, col.NumberFormat)}
- }
- case CalcOperatorMax:
- maxVal := -math.MaxFloat64
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
- for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
- val, _ := util.Convert2Float(content.String(false))
- if val > maxVal {
- maxVal = val
- }
- }
- }
- }
- if -math.MaxFloat64 != maxVal {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(maxVal, col.NumberFormat)}
- }
- case CalcOperatorRange:
- minVal := math.MaxFloat64
- maxVal := -math.MaxFloat64
- for _, row := range table.Rows {
- if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
- for _, content := range row.Cells[colIndex].Value.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 {
- col.Calc.Result = &Value{Number: NewFormattedValueNumber(maxVal-minVal, col.NumberFormat)}
- }
- }
-}
diff --git a/kernel/av/table_calc.go b/kernel/av/table_calc.go
new file mode 100644
index 000000000..6d097b4dd
--- /dev/null
+++ b/kernel/av/table_calc.go
@@ -0,0 +1,1446 @@
+// 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 .
+
+package av
+
+import (
+ "github.com/siyuan-note/siyuan/kernel/util"
+ "math"
+ "sort"
+)
+
+func (table *Table) CalcCols() {
+ for i, col := range table.Columns {
+ if nil == col.Calc {
+ continue
+ }
+
+ if CalcOperatorNone == col.Calc.Operator {
+ continue
+ }
+
+ switch col.Type {
+ case KeyTypeBlock:
+ table.calcColBlock(col, i)
+ case KeyTypeText:
+ table.calcColText(col, i)
+ case KeyTypeNumber:
+ table.calcColNumber(col, i)
+ case KeyTypeDate:
+ table.calcColDate(col, i)
+ case KeyTypeSelect:
+ table.calcColSelect(col, i)
+ case KeyTypeMSelect:
+ table.calcColMSelect(col, i)
+ case KeyTypeURL:
+ table.calcColURL(col, i)
+ case KeyTypeEmail:
+ table.calcColEmail(col, i)
+ case KeyTypePhone:
+ table.calcColPhone(col, i)
+ case KeyTypeMAsset:
+ table.calcColMAsset(col, i)
+ case KeyTypeTemplate:
+ table.calcColTemplate(col, i)
+ case KeyTypeCreated:
+ table.calcColCreated(col, i)
+ case KeyTypeUpdated:
+ table.calcColUpdated(col, i)
+ case KeyTypeCheckbox:
+ table.calcColCheckbox(col, i)
+ case KeyTypeRelation:
+ table.calcColRelation(col, i)
+ case KeyTypeRollup:
+ table.calcColRollup(col, i)
+ }
+ }
+}
+
+func (table *Table) calcColTemplate(col *TableColumn, colIndex int) {
+ switch col.Calc.Operator {
+ case CalcOperatorCountAll:
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
+ countValues++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
+ if !uniqueValues[row.Cells[colIndex].Value.Template.Content] {
+ uniqueValues[row.Cells[colIndex].Value.Template.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Template || "" == row.Cells[colIndex].Value.Template.Content {
+ countEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
+ countNotEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Template || "" == row.Cells[colIndex].Value.Template.Content {
+ countEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ case CalcOperatorSum:
+ sum := 0.0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
+ val, _ := util.Convert2Float(row.Cells[colIndex].Value.Template.Content)
+ sum += val
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(sum, col.NumberFormat)}
+ case CalcOperatorAverage:
+ sum := 0.0
+ count := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
+ val, _ := util.Convert2Float(row.Cells[colIndex].Value.Template.Content)
+ sum += val
+ count++
+ }
+ }
+ if 0 != count {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(sum/float64(count), col.NumberFormat)}
+ }
+ case CalcOperatorMedian:
+ values := []float64{}
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
+ val, _ := util.Convert2Float(row.Cells[colIndex].Value.Template.Content)
+ values = append(values, val)
+ }
+ }
+ sort.Float64s(values)
+ if len(values) > 0 {
+ if len(values)%2 == 0 {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber((values[len(values)/2-1]+values[len(values)/2])/2, col.NumberFormat)}
+ } else {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(values[len(values)/2], col.NumberFormat)}
+ }
+ }
+ case CalcOperatorMin:
+ minVal := math.MaxFloat64
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
+ val, _ := util.Convert2Float(row.Cells[colIndex].Value.Template.Content)
+ if val < minVal {
+ minVal = val
+ }
+ }
+ }
+ if math.MaxFloat64 != minVal {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(minVal, col.NumberFormat)}
+ }
+ case CalcOperatorMax:
+ maxVal := -math.MaxFloat64
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
+ val, _ := util.Convert2Float(row.Cells[colIndex].Value.Template.Content)
+ if val > maxVal {
+ maxVal = val
+ }
+ }
+ }
+ if -math.MaxFloat64 != maxVal {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(maxVal, col.NumberFormat)}
+ }
+ case CalcOperatorRange:
+ minVal := math.MaxFloat64
+ maxVal := -math.MaxFloat64
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Template && "" != row.Cells[colIndex].Value.Template.Content {
+ val, _ := util.Convert2Float(row.Cells[colIndex].Value.Template.Content)
+ if val < minVal {
+ minVal = val
+ }
+ if val > maxVal {
+ maxVal = val
+ }
+ }
+ }
+ if math.MaxFloat64 != minVal && -math.MaxFloat64 != maxVal {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(maxVal-minVal, col.NumberFormat)}
+ }
+ }
+}
+
+func (table *Table) calcColMAsset(col *TableColumn, colIndex int) {
+ switch col.Calc.Operator {
+ case CalcOperatorCountAll:
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MAsset && 0 < len(row.Cells[colIndex].Value.MAsset) {
+ countValues += len(row.Cells[colIndex].Value.MAsset)
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MAsset && 0 < len(row.Cells[colIndex].Value.MAsset) {
+ for _, sel := range row.Cells[colIndex].Value.MAsset {
+ if _, ok := uniqueValues[sel.Content]; !ok {
+ uniqueValues[sel.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.MAsset || 0 == len(row.Cells[colIndex].Value.MAsset) {
+ countEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MAsset && 0 < len(row.Cells[colIndex].Value.MAsset) {
+ countNotEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.MAsset || 0 == len(row.Cells[colIndex].Value.MAsset) {
+ countEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MAsset && 0 < len(row.Cells[colIndex].Value.MAsset) {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ }
+}
+
+func (table *Table) calcColMSelect(col *TableColumn, colIndex int) {
+ switch col.Calc.Operator {
+ case CalcOperatorCountAll:
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) {
+ countValues += len(row.Cells[colIndex].Value.MSelect)
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) {
+ for _, sel := range row.Cells[colIndex].Value.MSelect {
+ if _, ok := uniqueValues[sel.Content]; !ok {
+ uniqueValues[sel.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.MSelect || 0 == len(row.Cells[colIndex].Value.MSelect) {
+ countEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) {
+ countNotEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.MSelect || 0 == len(row.Cells[colIndex].Value.MSelect) {
+ countEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ }
+}
+
+func (table *Table) calcColSelect(col *TableColumn, colIndex int) {
+ switch col.Calc.Operator {
+ case CalcOperatorCountAll:
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) && nil != row.Cells[colIndex].Value.MSelect[0] && "" != row.Cells[colIndex].Value.MSelect[0].Content {
+ countValues++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) && nil != row.Cells[colIndex].Value.MSelect[0] && "" != row.Cells[colIndex].Value.MSelect[0].Content {
+ if _, ok := uniqueValues[row.Cells[colIndex].Value.MSelect[0].Content]; !ok {
+ uniqueValues[row.Cells[colIndex].Value.MSelect[0].Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.MSelect || 1 > len(row.Cells[colIndex].Value.MSelect) || nil == row.Cells[colIndex].Value.MSelect[0] || "" == row.Cells[colIndex].Value.MSelect[0].Content {
+ countEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) && nil != row.Cells[colIndex].Value.MSelect[0] && "" != row.Cells[colIndex].Value.MSelect[0].Content {
+ countNotEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.MSelect || 1 > len(row.Cells[colIndex].Value.MSelect) || nil == row.Cells[colIndex].Value.MSelect[0] || "" == row.Cells[colIndex].Value.MSelect[0].Content {
+ countEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.MSelect && 0 < len(row.Cells[colIndex].Value.MSelect) && nil != row.Cells[colIndex].Value.MSelect[0] && "" != row.Cells[colIndex].Value.MSelect[0].Content {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ }
+}
+
+func (table *Table) calcColDate(col *TableColumn, colIndex int) {
+ switch col.Calc.Operator {
+ case CalcOperatorCountAll:
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Date && row.Cells[colIndex].Value.Date.IsNotEmpty {
+ countValues++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[int64]bool{}
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Date && row.Cells[colIndex].Value.Date.IsNotEmpty {
+ if _, ok := uniqueValues[row.Cells[colIndex].Value.Date.Content]; !ok {
+ countUniqueValues++
+ uniqueValues[row.Cells[colIndex].Value.Date.Content] = true
+ }
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Date || !row.Cells[colIndex].Value.Date.IsNotEmpty {
+ countEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Date && row.Cells[colIndex].Value.Date.IsNotEmpty {
+ countNotEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Date || !row.Cells[colIndex].Value.Date.IsNotEmpty {
+ countEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Date && row.Cells[colIndex].Value.Date.IsNotEmpty {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ case CalcOperatorEarliest:
+ earliest := int64(0)
+ var isNotTime, hasEndDate bool
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Date && row.Cells[colIndex].Value.Date.IsNotEmpty {
+ if 0 == earliest || earliest > row.Cells[colIndex].Value.Date.Content {
+ earliest = row.Cells[colIndex].Value.Date.Content
+ isNotTime = row.Cells[colIndex].Value.Date.IsNotTime
+ hasEndDate = row.Cells[colIndex].Value.Date.HasEndDate
+ }
+ }
+ }
+ if 0 != earliest {
+ col.Calc.Result = &Value{Date: NewFormattedValueDate(earliest, 0, DateFormatNone, isNotTime, hasEndDate)}
+ }
+ case CalcOperatorLatest:
+ latest := int64(0)
+ var isNotTime, hasEndDate bool
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Date && row.Cells[colIndex].Value.Date.IsNotEmpty {
+ if 0 == latest || latest < row.Cells[colIndex].Value.Date.Content {
+ latest = row.Cells[colIndex].Value.Date.Content
+ isNotTime = row.Cells[colIndex].Value.Date.IsNotTime
+ hasEndDate = row.Cells[colIndex].Value.Date.HasEndDate
+ }
+ }
+ }
+ if 0 != latest {
+ col.Calc.Result = &Value{Date: NewFormattedValueDate(latest, 0, DateFormatNone, isNotTime, hasEndDate)}
+ }
+ case CalcOperatorRange:
+ earliest := int64(0)
+ latest := int64(0)
+ var isNotTime, hasEndDate bool
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Date && row.Cells[colIndex].Value.Date.IsNotEmpty {
+ if 0 == earliest || earliest > row.Cells[colIndex].Value.Date.Content {
+ earliest = row.Cells[colIndex].Value.Date.Content
+ isNotTime = row.Cells[colIndex].Value.Date.IsNotTime
+ hasEndDate = row.Cells[colIndex].Value.Date.HasEndDate
+ }
+ if 0 == latest || latest < row.Cells[colIndex].Value.Date.Content {
+ latest = row.Cells[colIndex].Value.Date.Content
+ isNotTime = row.Cells[colIndex].Value.Date.IsNotTime
+ hasEndDate = row.Cells[colIndex].Value.Date.HasEndDate
+ }
+ }
+ }
+ if 0 != earliest && 0 != latest {
+ col.Calc.Result = &Value{Date: NewFormattedValueDate(earliest, latest, DateFormatDuration, isNotTime, hasEndDate)}
+ }
+ }
+}
+
+func (table *Table) calcColNumber(col *TableColumn, colIndex int) {
+ switch col.Calc.Operator {
+ case CalcOperatorCountAll:
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
+ countValues++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[float64]bool{}
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
+ if !uniqueValues[row.Cells[colIndex].Value.Number.Content] {
+ uniqueValues[row.Cells[colIndex].Value.Number.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Number || !row.Cells[colIndex].Value.Number.IsNotEmpty {
+ countEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
+ countNotEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Number || !row.Cells[colIndex].Value.Number.IsNotEmpty {
+ countEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ case CalcOperatorSum:
+ sum := 0.0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
+ sum += row.Cells[colIndex].Value.Number.Content
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(sum, col.NumberFormat)}
+ case CalcOperatorAverage:
+ sum := 0.0
+ count := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
+ sum += row.Cells[colIndex].Value.Number.Content
+ count++
+ }
+ }
+ if 0 != count {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(sum/float64(count), col.NumberFormat)}
+ }
+ case CalcOperatorMedian:
+ values := []float64{}
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
+ values = append(values, row.Cells[colIndex].Value.Number.Content)
+ }
+ }
+ sort.Float64s(values)
+ if len(values) > 0 {
+ if len(values)%2 == 0 {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber((values[len(values)/2-1]+values[len(values)/2])/2, col.NumberFormat)}
+ } else {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(values[len(values)/2], col.NumberFormat)}
+ }
+ }
+ case CalcOperatorMin:
+ minVal := math.MaxFloat64
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
+ if row.Cells[colIndex].Value.Number.Content < minVal {
+ minVal = row.Cells[colIndex].Value.Number.Content
+ }
+ }
+ }
+ if math.MaxFloat64 != minVal {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(minVal, col.NumberFormat)}
+ }
+ case CalcOperatorMax:
+ maxVal := -math.MaxFloat64
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
+ if row.Cells[colIndex].Value.Number.Content > maxVal {
+ maxVal = row.Cells[colIndex].Value.Number.Content
+ }
+ }
+ }
+ if -math.MaxFloat64 != maxVal {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(maxVal, col.NumberFormat)}
+ }
+ case CalcOperatorRange:
+ minVal := math.MaxFloat64
+ maxVal := -math.MaxFloat64
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Number && row.Cells[colIndex].Value.Number.IsNotEmpty {
+ if row.Cells[colIndex].Value.Number.Content < minVal {
+ minVal = row.Cells[colIndex].Value.Number.Content
+ }
+ if row.Cells[colIndex].Value.Number.Content > maxVal {
+ maxVal = row.Cells[colIndex].Value.Number.Content
+ }
+ }
+ }
+ if math.MaxFloat64 != minVal && -math.MaxFloat64 != maxVal {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(maxVal-minVal, col.NumberFormat)}
+ }
+ }
+}
+
+func (table *Table) calcColText(col *TableColumn, colIndex int) {
+ switch col.Calc.Operator {
+ case CalcOperatorCountAll:
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Text && "" != row.Cells[colIndex].Value.Text.Content {
+ countValues++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Text && "" != row.Cells[colIndex].Value.Text.Content {
+ if !uniqueValues[row.Cells[colIndex].Value.Text.Content] {
+ uniqueValues[row.Cells[colIndex].Value.Text.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Text || "" == row.Cells[colIndex].Value.Text.Content {
+ countEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Text && "" != row.Cells[colIndex].Value.Text.Content {
+ countNotEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Text || "" == row.Cells[colIndex].Value.Text.Content {
+ countEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Text && "" != row.Cells[colIndex].Value.Text.Content {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ }
+}
+
+func (table *Table) calcColURL(col *TableColumn, colIndex int) {
+ switch col.Calc.Operator {
+ case CalcOperatorCountAll:
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.URL && "" != row.Cells[colIndex].Value.URL.Content {
+ countValues++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.URL && "" != row.Cells[colIndex].Value.URL.Content {
+ if !uniqueValues[row.Cells[colIndex].Value.URL.Content] {
+ uniqueValues[row.Cells[colIndex].Value.URL.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.URL || "" == row.Cells[colIndex].Value.URL.Content {
+ countEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.URL && "" != row.Cells[colIndex].Value.URL.Content {
+ countNotEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.URL || "" == row.Cells[colIndex].Value.URL.Content {
+ countEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.URL && "" != row.Cells[colIndex].Value.URL.Content {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ }
+}
+
+func (table *Table) calcColEmail(col *TableColumn, colIndex int) {
+ switch col.Calc.Operator {
+ case CalcOperatorCountAll:
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Email && "" != row.Cells[colIndex].Value.Email.Content {
+ countValues++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Email && "" != row.Cells[colIndex].Value.Email.Content {
+ if !uniqueValues[row.Cells[colIndex].Value.Email.Content] {
+ uniqueValues[row.Cells[colIndex].Value.Email.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Email || "" == row.Cells[colIndex].Value.Email.Content {
+ countEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Email && "" != row.Cells[colIndex].Value.Email.Content {
+ countNotEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Email || "" == row.Cells[colIndex].Value.Email.Content {
+ countEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Email && "" != row.Cells[colIndex].Value.Email.Content {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ }
+}
+
+func (table *Table) calcColPhone(col *TableColumn, colIndex int) {
+ switch col.Calc.Operator {
+ case CalcOperatorCountAll:
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Phone && "" != row.Cells[colIndex].Value.Phone.Content {
+ countValues++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Phone && "" != row.Cells[colIndex].Value.Phone.Content {
+ if !uniqueValues[row.Cells[colIndex].Value.Phone.Content] {
+ uniqueValues[row.Cells[colIndex].Value.Phone.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Phone || "" == row.Cells[colIndex].Value.Phone.Content {
+ countEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Phone && "" != row.Cells[colIndex].Value.Phone.Content {
+ countNotEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Phone || "" == row.Cells[colIndex].Value.Phone.Content {
+ countEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Phone && "" != row.Cells[colIndex].Value.Phone.Content {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ }
+}
+
+func (table *Table) calcColBlock(col *TableColumn, colIndex int) {
+ switch col.Calc.Operator {
+ case CalcOperatorCountAll:
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Block && "" != row.Cells[colIndex].Value.Block.Content {
+ countValues++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Block && "" != row.Cells[colIndex].Value.Block.Content {
+ if !uniqueValues[row.Cells[colIndex].Value.Block.Content] {
+ uniqueValues[row.Cells[colIndex].Value.Block.Content] = true
+ countUniqueValues++
+ }
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Block || "" == row.Cells[colIndex].Value.Block.Content {
+ countEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Block && "" != row.Cells[colIndex].Value.Block.Content {
+ countNotEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Block || "" == row.Cells[colIndex].Value.Block.Content {
+ countEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Block && "" != row.Cells[colIndex].Value.Block.Content {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ }
+}
+
+func (table *Table) calcColCreated(col *TableColumn, colIndex int) {
+ switch col.Calc.Operator {
+ case CalcOperatorCountAll:
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Created {
+ countValues++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[int64]bool{}
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Created {
+ if _, ok := uniqueValues[row.Cells[colIndex].Value.Created.Content]; !ok {
+ countUniqueValues++
+ uniqueValues[row.Cells[colIndex].Value.Created.Content] = true
+ }
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Created {
+ countEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Created {
+ countNotEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Created {
+ countEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Created {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ case CalcOperatorEarliest:
+ earliest := int64(0)
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Created {
+ if 0 == earliest || earliest > row.Cells[colIndex].Value.Created.Content {
+ earliest = row.Cells[colIndex].Value.Created.Content
+ }
+ }
+ }
+ if 0 != earliest {
+ col.Calc.Result = &Value{Created: NewFormattedValueCreated(earliest, 0, CreatedFormatNone)}
+ }
+ case CalcOperatorLatest:
+ latest := int64(0)
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Created {
+ if 0 == latest || latest < row.Cells[colIndex].Value.Created.Content {
+ latest = row.Cells[colIndex].Value.Created.Content
+ }
+ }
+ }
+ if 0 != latest {
+ col.Calc.Result = &Value{Created: NewFormattedValueCreated(latest, 0, CreatedFormatNone)}
+ }
+ case CalcOperatorRange:
+ earliest := int64(0)
+ latest := int64(0)
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Created {
+ if 0 == earliest || earliest > row.Cells[colIndex].Value.Created.Content {
+ earliest = row.Cells[colIndex].Value.Created.Content
+ }
+ if 0 == latest || latest < row.Cells[colIndex].Value.Created.Content {
+ latest = row.Cells[colIndex].Value.Created.Content
+ }
+ }
+ }
+ if 0 != earliest && 0 != latest {
+ col.Calc.Result = &Value{Created: NewFormattedValueCreated(earliest, latest, CreatedFormatDuration)}
+ }
+ }
+}
+
+func (table *Table) calcColUpdated(col *TableColumn, colIndex int) {
+ switch col.Calc.Operator {
+ case CalcOperatorCountAll:
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Updated && row.Cells[colIndex].Value.Updated.IsNotEmpty {
+ countValues++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[int64]bool{}
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Updated && row.Cells[colIndex].Value.Updated.IsNotEmpty {
+ if _, ok := uniqueValues[row.Cells[colIndex].Value.Updated.Content]; !ok {
+ countUniqueValues++
+ uniqueValues[row.Cells[colIndex].Value.Updated.Content] = true
+ }
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Updated || !row.Cells[colIndex].Value.Updated.IsNotEmpty {
+ countEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Updated && row.Cells[colIndex].Value.Updated.IsNotEmpty {
+ countNotEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Updated || !row.Cells[colIndex].Value.Updated.IsNotEmpty {
+ countEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Updated && row.Cells[colIndex].Value.Updated.IsNotEmpty {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ case CalcOperatorEarliest:
+ earliest := int64(0)
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Updated && row.Cells[colIndex].Value.Updated.IsNotEmpty {
+ if 0 == earliest || earliest > row.Cells[colIndex].Value.Updated.Content {
+ earliest = row.Cells[colIndex].Value.Updated.Content
+ }
+ }
+ }
+ if 0 != earliest {
+ col.Calc.Result = &Value{Updated: NewFormattedValueUpdated(earliest, 0, UpdatedFormatNone)}
+ }
+ case CalcOperatorLatest:
+ latest := int64(0)
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Updated && row.Cells[colIndex].Value.Updated.IsNotEmpty {
+ if 0 == latest || latest < row.Cells[colIndex].Value.Updated.Content {
+ latest = row.Cells[colIndex].Value.Updated.Content
+ }
+ }
+ }
+ if 0 != latest {
+ col.Calc.Result = &Value{Updated: NewFormattedValueUpdated(latest, 0, UpdatedFormatNone)}
+ }
+ case CalcOperatorRange:
+ earliest := int64(0)
+ latest := int64(0)
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Updated && row.Cells[colIndex].Value.Updated.IsNotEmpty {
+ if 0 == earliest || earliest > row.Cells[colIndex].Value.Updated.Content {
+ earliest = row.Cells[colIndex].Value.Updated.Content
+ }
+ if 0 == latest || latest < row.Cells[colIndex].Value.Updated.Content {
+ latest = row.Cells[colIndex].Value.Updated.Content
+ }
+ }
+ }
+ if 0 != earliest && 0 != latest {
+ col.Calc.Result = &Value{Updated: NewFormattedValueUpdated(earliest, latest, UpdatedFormatDuration)}
+ }
+ }
+}
+
+func (table *Table) calcColCheckbox(col *TableColumn, colIndex int) {
+ switch col.Calc.Operator {
+ case CalcOperatorCountAll:
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
+ case CalcOperatorChecked:
+ countChecked := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Checkbox && row.Cells[colIndex].Value.Checkbox.Checked {
+ countChecked++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countChecked), NumberFormatNone)}
+ case CalcOperatorUnchecked:
+ countUnchecked := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Checkbox && !row.Cells[colIndex].Value.Checkbox.Checked {
+ countUnchecked++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUnchecked), NumberFormatNone)}
+ case CalcOperatorPercentChecked:
+ countChecked := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Checkbox && row.Cells[colIndex].Value.Checkbox.Checked {
+ countChecked++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countChecked)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentUnchecked:
+ countUnchecked := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Checkbox && !row.Cells[colIndex].Value.Checkbox.Checked {
+ countUnchecked++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUnchecked)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ }
+}
+
+func (table *Table) calcColRelation(col *TableColumn, colIndex int) {
+ switch col.Calc.Operator {
+ case CalcOperatorCountAll:
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Relation {
+ countValues++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Relation {
+ for _, id := range row.Cells[colIndex].Value.Relation.BlockIDs {
+ if !uniqueValues[id] {
+ uniqueValues[id] = true
+ countUniqueValues++
+ }
+ }
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Relation || 0 == len(row.Cells[colIndex].Value.Relation.BlockIDs) {
+ countEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Relation && 0 < len(row.Cells[colIndex].Value.Relation.BlockIDs) {
+ countNotEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Relation || 0 == len(row.Cells[colIndex].Value.Relation.BlockIDs) {
+ countEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Relation && 0 < len(row.Cells[colIndex].Value.Relation.BlockIDs) {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ }
+}
+
+func (table *Table) calcColRollup(col *TableColumn, colIndex int) {
+ switch col.Calc.Operator {
+ case CalcOperatorCountAll:
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(len(table.Rows)), NumberFormatNone)}
+ case CalcOperatorCountValues:
+ countValues := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup {
+ countValues++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countValues), NumberFormatNone)}
+ case CalcOperatorCountUniqueValues:
+ countUniqueValues := 0
+ uniqueValues := map[string]bool{}
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup {
+ for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
+ if !uniqueValues[content.String(true)] {
+ uniqueValues[content.String(true)] = true
+ countUniqueValues++
+ }
+ }
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countUniqueValues), NumberFormatNone)}
+ case CalcOperatorCountEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Rollup || 0 == len(row.Cells[colIndex].Value.Rollup.Contents) {
+ countEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty), NumberFormatNone)}
+ case CalcOperatorCountNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
+ countNotEmpty++
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty), NumberFormatNone)}
+ case CalcOperatorPercentEmpty:
+ countEmpty := 0
+ for _, row := range table.Rows {
+ if nil == row.Cells[colIndex] || nil == row.Cells[colIndex].Value || nil == row.Cells[colIndex].Value.Rollup || 0 == len(row.Cells[colIndex].Value.Rollup.Contents) {
+ countEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ case CalcOperatorPercentNotEmpty:
+ countNotEmpty := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
+ countNotEmpty++
+ }
+ }
+ if 0 < len(table.Rows) {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(float64(countNotEmpty)/float64(len(table.Rows)), NumberFormatPercent)}
+ }
+ case CalcOperatorSum:
+ sum := 0.0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
+ for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
+ val, _ := util.Convert2Float(content.String(false))
+ sum += val
+ }
+ }
+ }
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(sum, col.NumberFormat)}
+ case CalcOperatorAverage:
+ sum := 0.0
+ count := 0
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
+ for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
+ val, _ := util.Convert2Float(content.String(false))
+ sum += val
+ count++
+ }
+ }
+ }
+ if 0 != count {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(sum/float64(count), col.NumberFormat)}
+ }
+ case CalcOperatorMedian:
+ values := []float64{}
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
+ for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
+ val, _ := util.Convert2Float(content.String(false))
+ values = append(values, val)
+ }
+ }
+ }
+ sort.Float64s(values)
+ if 0 < len(values) {
+ if 0 == len(values)%2 {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber((values[len(values)/2-1]+values[len(values)/2])/2, col.NumberFormat)}
+ } else {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(values[len(values)/2], col.NumberFormat)}
+ }
+ }
+ case CalcOperatorMin:
+ minVal := math.MaxFloat64
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
+ for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
+ val, _ := util.Convert2Float(content.String(false))
+ if val < minVal {
+ minVal = val
+ }
+ }
+ }
+ }
+ if math.MaxFloat64 != minVal {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(minVal, col.NumberFormat)}
+ }
+ case CalcOperatorMax:
+ maxVal := -math.MaxFloat64
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
+ for _, content := range row.Cells[colIndex].Value.Rollup.Contents {
+ val, _ := util.Convert2Float(content.String(false))
+ if val > maxVal {
+ maxVal = val
+ }
+ }
+ }
+ }
+ if -math.MaxFloat64 != maxVal {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(maxVal, col.NumberFormat)}
+ }
+ case CalcOperatorRange:
+ minVal := math.MaxFloat64
+ maxVal := -math.MaxFloat64
+ for _, row := range table.Rows {
+ if nil != row.Cells[colIndex] && nil != row.Cells[colIndex].Value && nil != row.Cells[colIndex].Value.Rollup && 0 < len(row.Cells[colIndex].Value.Rollup.Contents) {
+ for _, content := range row.Cells[colIndex].Value.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 {
+ col.Calc.Result = &Value{Number: NewFormattedValueNumber(maxVal-minVal, col.NumberFormat)}
+ }
+ }
+}