data_table.go 4.0 KB
package domain

import (
	"strings"
)

type DataTable struct {
	Fields []*Field   `json:"fields"`
	Data   [][]string `json:"data"`
	Total  int64      `json:"total"`
}

type Where struct {
	PageNumber int         `json:"pageNumber"`
	PageSize   int         `json:"pageSize"`
	HeaderRow  int         `json:"headerRow"` // 行号 默认:0
	Conditions []Condition `json:"conditions"`
}

func (w Where) Offset() int {
	if w.PageNumber == 0 && w.PageSize == 0 {
		return 0
	}
	return (w.PageNumber - 1) * w.PageSize
}

func (w Where) ValidSql() (err error) {
	for _, c := range w.Conditions {
		if err = SqlDetections(c.Like); err != nil {
			return err
		}
		//if err = SqlDetections(c.In...); err != nil {
		//	return err
		//}
		//if err = SqlDetections(c.Ex...); err != nil {
		//	return err
		//}
		if err = SqlDetections(c.Order); err != nil {
			return err
		}
		for _, r := range c.Range {
			if err = SqlDetections(r.Val); err != nil {
				return err
			}
		}
	}
	return
}

type Condition struct {
	Field *Field        `json:"field"`
	Like  string        `json:"like"`
	In    []interface{} `json:"in"`
	Ex    []interface{} `json:"ex"`
	Range []RangStruct  `json:"range"`
	Order string        `json:"order"`
}

func (t *DataTable) OptionalValue(args ...string) []string {
	var values = make([]string, 0)
	match := ""
	filedType := ""
	if len(args) > 0 {
		match = args[0]
	}
	if len(args) > 1 {
		filedType = args[1]
	}
	if len(t.Data) > 0 && len(t.Data[0]) == 1 {
		for i := range t.Data {
			if len(t.Data[i]) == 0 {
				continue
			}
			if len(match) > 0 && !strings.Contains(t.Data[i][0], match) {
				continue
			}
			if filedType == Float.ToString() || filedType == Date.ToString() {
				values = append(values, RoundFieldValue(&Field{SQLType: filedType}, t.Data[i][0]))
				continue
			}
			values = append(values, t.Data[i][0])
		}
	}
	return values
}

func (t *DataTable) Values(f *Field) []string {
	var res = make([]string, 0)
	index := -1
	for i := range t.Fields {
		if t.Fields[i].SQLName == f.SQLName {
			index = i
			break
		}
		if t.Fields[i].Name == f.SQLName {
			index = i
			break
		}
	}
	if index < 0 {
		return res
	}
	for i := range t.Data {
		for j := range t.Data[i] {
			if j == index {
				res = append(res, RoundFieldValue(f, t.Data[i][j]))
				break
			}
		}
	}
	return res
}

func (t *DataTable) MatchFields(from []*Field) []*Field {
	return from
}

func (t *DataTable) FilterByWhere(where Where) (response [][]string, length int64) {
	pageNumber, pageSize := where.PageNumber, where.PageSize
	response = make([][]string, 0)
	wrapperFilters := func(data []string, next ...func([]string) bool) ([]string, bool) {
		ok := true
		for i := range next {
			if !next[i](data) {
				ok = false
			}
			if !ok {
				break
			}
		}
		if !ok {
			return nil, false
		}
		return data, true
	}
	filterFuncList := make([]func([]string) bool, 0)
	for _, c := range where.Conditions {
		var index = 0
		var filed *Field
		for i, f := range t.Fields {
			if f.Name == c.Field.Name {
				index = i
				filed = f
				break
			}
		}
		if filed == nil {
			continue
		}
		if len(c.In) > 0 {
			filterFuncList = append(filterFuncList, WithInFilter(c.In, index))
		}
	}
	for _, data := range t.Data {
		if v, ok := wrapperFilters(data, filterFuncList...); ok {
			response = append(response, v)
		}
	}
	length = int64(len(response))
	response = pageData(pageNumber, pageSize, response)
	return
}

type RangStruct struct {
	Op  string      `json:"op"`
	Val interface{} `json:"val"`
}

func pageData(pageNumber, pageSize int, data [][]string) [][]string {
	if pageNumber == 0 || pageSize == 0 {
		return data
	}
	offset := (pageNumber - 1) * pageSize
	if len(data) < offset {
		return [][]string{}
	}
	if len(data) < offset+pageSize {
		pageSize = len(data) - offset
	}
	return data[offset : offset+pageSize]
}

func WithInFilter(in []interface{}, index int) func(data []string) bool {
	return func(data []string) bool {
		if len(data) < index {
			return false
		}
		for _, item := range in {
			if data[index] == item.(string) {
				return true
			}
		}
		return false
	}
}