github.com/tobgu/qframe@v0.4.0/internal/template/column.go (about) 1 package template 2 3 // Code generated from template/column.go DO NOT EDIT 4 5 import ( 6 "fmt" 7 "github.com/tobgu/qframe/config/rolling" 8 9 "github.com/mauricelam/genny/generic" 10 "github.com/tobgu/qframe/internal/column" 11 "github.com/tobgu/qframe/internal/index" 12 "github.com/tobgu/qframe/qerrors" 13 ) 14 15 type genericDataType generic.Number 16 17 //go:generate genny -in=$GOFILE -out=../icolumn/column_gen.go -pkg=icolumn gen "genericDataType=int" 18 //go:generate genny -in=$GOFILE -out=../fcolumn/column_gen.go -pkg=fcolumn gen "genericDataType=float64" 19 //go:generate genny -in=$GOFILE -out=../bcolumn/column_gen.go -pkg=bcolumn gen "genericDataType=bool" 20 21 type Column struct { 22 data []genericDataType 23 } 24 25 func New(d []genericDataType) Column { 26 return Column{data: d} 27 } 28 29 func NewConst(val genericDataType, count int) Column { 30 var nullVal genericDataType 31 data := make([]genericDataType, count) 32 if val != nullVal { 33 for i := range data { 34 data[i] = val 35 } 36 } 37 38 return Column{data: data} 39 } 40 41 func (c Column) fnName(name string) string { 42 return fmt.Sprintf("%s.%s", c.DataType(), name) 43 } 44 45 // Apply single argument function. The result may be a column 46 // of a different type than the current column. 47 func (c Column) Apply1(fn interface{}, ix index.Int) (interface{}, error) { 48 switch t := fn.(type) { 49 case func(genericDataType) int: 50 result := make([]int, len(c.data)) 51 for _, i := range ix { 52 result[i] = t(c.data[i]) 53 } 54 return result, nil 55 case func(genericDataType) float64: 56 result := make([]float64, len(c.data)) 57 for _, i := range ix { 58 result[i] = t(c.data[i]) 59 } 60 return result, nil 61 case func(genericDataType) bool: 62 result := make([]bool, len(c.data)) 63 for _, i := range ix { 64 result[i] = t(c.data[i]) 65 } 66 return result, nil 67 case func(genericDataType) *string: 68 result := make([]*string, len(c.data)) 69 for _, i := range ix { 70 result[i] = t(c.data[i]) 71 } 72 return result, nil 73 default: 74 return nil, qerrors.New(c.fnName("Apply1"), "cannot apply type %#v to column", fn) 75 } 76 } 77 78 // Apply double argument function to two columns. Both columns must have the 79 // same type. The resulting column will have the same type as this column. 80 func (c Column) Apply2(fn interface{}, s2 column.Column, ix index.Int) (column.Column, error) { 81 ss2, ok := s2.(Column) 82 if !ok { 83 return Column{}, qerrors.New(c.fnName("Apply2"), "invalid column type: %s", s2.DataType()) 84 } 85 86 t, ok := fn.(func(genericDataType, genericDataType) genericDataType) 87 if !ok { 88 return Column{}, qerrors.New("Apply2", "invalid function type: %#v", fn) 89 } 90 91 result := make([]genericDataType, len(c.data)) 92 for _, i := range ix { 93 result[i] = t(c.data[i], ss2.data[i]) 94 } 95 96 return New(result), nil 97 } 98 99 func (c Column) subset(index index.Int) Column { 100 data := make([]genericDataType, len(index)) 101 for i, ix := range index { 102 data[i] = c.data[ix] 103 } 104 105 return Column{data: data} 106 } 107 108 func (c Column) Subset(index index.Int) column.Column { 109 return c.subset(index) 110 } 111 112 func (c Column) Comparable(reverse, equalNull, nullLast bool) column.Comparable { 113 result := Comparable{data: c.data, ltValue: column.LessThan, gtValue: column.GreaterThan, nullLtValue: column.LessThan, nullGtValue: column.GreaterThan, equalNullValue: column.NotEqual} 114 if reverse { 115 result.ltValue, result.nullLtValue, result.gtValue, result.nullGtValue = 116 result.gtValue, result.nullGtValue, result.ltValue, result.nullLtValue 117 } 118 119 if nullLast { 120 result.nullLtValue, result.nullGtValue = result.nullGtValue, result.nullLtValue 121 } 122 123 if equalNull { 124 result.equalNullValue = column.Equal 125 } 126 127 return result 128 } 129 130 func (c Column) String() string { 131 return fmt.Sprintf("%v", c.data) 132 } 133 134 func (c Column) Len() int { 135 return len(c.data) 136 } 137 138 func (c Column) Aggregate(indices []index.Int, fn interface{}) (column.Column, error) { 139 var actualFn func([]genericDataType) genericDataType 140 var ok bool 141 142 switch t := fn.(type) { 143 case string: 144 actualFn, ok = aggregations[t] 145 if !ok { 146 return nil, qerrors.New(c.fnName("Aggregate"), "aggregation function %c is not defined for column", fn) 147 } 148 case func([]genericDataType) genericDataType: 149 actualFn = t 150 default: 151 return nil, qerrors.New(c.fnName("Aggregate"), "invalid aggregation function type: %v", t) 152 } 153 154 data := make([]genericDataType, 0, len(indices)) 155 var buf []genericDataType 156 for _, ix := range indices { 157 subS := c.subsetWithBuf(ix, &buf) 158 data = append(data, actualFn(subS.data)) 159 } 160 161 return Column{data: data}, nil 162 } 163 164 func (c Column) subsetWithBuf(index index.Int, buf *[]genericDataType) Column { 165 if cap(*buf) < len(index) { 166 *buf = make([]genericDataType, 0, len(index)) 167 } 168 169 data := (*buf)[:0] 170 for _, ix := range index { 171 data = append(data, c.data[ix]) 172 } 173 174 return Column{data: data} 175 } 176 177 func (c Column) View(ix index.Int) View { 178 return View{data: c.data, index: ix} 179 } 180 181 func (c Column) Rolling(fn interface{}, ix index.Int, config rolling.Config) (column.Column, error) { 182 return c, nil 183 } 184 185 type Comparable struct { 186 data []genericDataType 187 ltValue column.CompareResult 188 nullLtValue column.CompareResult 189 gtValue column.CompareResult 190 nullGtValue column.CompareResult 191 equalNullValue column.CompareResult 192 } 193 194 // View is a view into a column that allows access to individual elements by index. 195 type View struct { 196 data []genericDataType 197 index index.Int 198 } 199 200 // ItemAt returns the value at position i. 201 func (v View) ItemAt(i int) genericDataType { 202 return v.data[v.index[i]] 203 } 204 205 // Len returns the column length. 206 func (v View) Len() int { 207 return len(v.index) 208 } 209 210 // Slice returns a slice containing a copy of the column data. 211 func (v View) Slice() []genericDataType { 212 // TODO: This forces an alloc, as an alternative a slice could be taken 213 // as input that can be (re)used by the client. Are there use cases 214 // where this would actually make sense? 215 result := make([]genericDataType, v.Len()) 216 for i, j := range v.index { 217 result[i] = v.data[j] 218 } 219 return result 220 }