github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/pkg/database/query_fields.go (about) 1 // Copyright © 2021 Kaleido, Inc. 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 package database 18 19 import ( 20 "context" 21 "database/sql" 22 "database/sql/driver" 23 "encoding/json" 24 "fmt" 25 "reflect" 26 "strconv" 27 "strings" 28 29 "github.com/kaleido-io/firefly/internal/i18n" 30 "github.com/kaleido-io/firefly/pkg/fftypes" 31 ) 32 33 // QueryFactory creates a filter builder in the given context, and contains the rules on 34 // which fields can be used by the builder (and how they are serialized) 35 type QueryFactory interface { 36 NewFilter(ctx context.Context) FilterBuilder 37 NewFilterLimit(ctx context.Context, defLimit uint64) FilterBuilder 38 NewUpdate(ctx context.Context) UpdateBuilder 39 } 40 41 type queryFields map[string]Field 42 43 func (qf *queryFields) NewFilterLimit(ctx context.Context, defLimit uint64) FilterBuilder { 44 return &filterBuilder{ 45 ctx: ctx, 46 queryFields: *qf, 47 limit: defLimit, 48 } 49 } 50 51 func (qf *queryFields) NewFilter(ctx context.Context) FilterBuilder { 52 return qf.NewFilterLimit(ctx, 0) 53 } 54 55 func (qf *queryFields) NewUpdate(ctx context.Context) UpdateBuilder { 56 return &updateBuilder{ 57 ctx: ctx, 58 queryFields: *qf, 59 } 60 } 61 62 // FieldSerialization - we stand on the shoulders of the well adopted SQL serialization interface here to help us define what 63 // string<->value looks like, even though this plugin interface is not tightly coupled to SQL. 64 type FieldSerialization interface { 65 driver.Valuer 66 sql.Scanner // Implementations can assume the value is ALWAYS a string 67 } 68 69 type Field interface { 70 getSerialization() FieldSerialization 71 } 72 73 type StringField struct{} 74 type stringField struct{ s string } 75 76 func (f *stringField) Scan(src interface{}) error { 77 switch tv := src.(type) { 78 case string: 79 f.s = tv 80 case int: 81 f.s = strconv.FormatInt(int64(tv), 10) 82 case int32: 83 f.s = strconv.FormatInt(int64(tv), 10) 84 case int64: 85 f.s = strconv.FormatInt(tv, 10) 86 case uint: 87 f.s = strconv.FormatInt(int64(tv), 10) 88 case uint32: 89 f.s = strconv.FormatInt(int64(tv), 10) 90 case uint64: 91 f.s = strconv.FormatInt(int64(tv), 10) 92 case *fftypes.UUID: 93 if tv != nil { 94 f.s = tv.String() 95 } 96 case fftypes.UUID: 97 f.s = tv.String() 98 case *fftypes.Bytes32: 99 if tv != nil { 100 f.s = tv.String() 101 } 102 case fftypes.Bytes32: 103 f.s = tv.String() 104 case nil: 105 default: 106 if reflect.TypeOf(tv).Kind() == reflect.String { 107 // This is helpful for status enums 108 f.s = reflect.ValueOf(tv).String() 109 } else { 110 return i18n.NewError(context.Background(), i18n.MsgScanFailed, src, f.s) 111 } 112 } 113 return nil 114 } 115 func (f *stringField) Value() (driver.Value, error) { return f.s, nil } 116 func (f *stringField) String() string { return f.s } 117 func (f *StringField) getSerialization() FieldSerialization { return &stringField{} } 118 119 type UUIDField struct{} 120 type uuidField struct{ u *fftypes.UUID } 121 122 func (f *uuidField) Scan(src interface{}) (err error) { 123 switch tv := src.(type) { 124 case string: 125 if tv == "" { 126 f.u = nil 127 return nil 128 } 129 f.u, err = fftypes.ParseUUID(context.Background(), tv) 130 return err 131 case *fftypes.UUID: 132 f.u = tv 133 case fftypes.UUID: 134 u := tv 135 f.u = &u 136 case *fftypes.Bytes32: 137 if tv == nil { 138 f.u = nil 139 return nil 140 } 141 var u fftypes.UUID 142 copy(u[:], tv[0:16]) 143 f.u = &u 144 case fftypes.Bytes32: 145 var u fftypes.UUID 146 copy(u[:], tv[0:16]) 147 f.u = &u 148 case nil: 149 default: 150 return i18n.NewError(context.Background(), i18n.MsgScanFailed, src, f.u) 151 } 152 return nil 153 } 154 func (f *uuidField) Value() (driver.Value, error) { return f.u.Value() } 155 func (f *uuidField) String() string { return fmt.Sprintf("%v", f.u) } 156 func (f *UUIDField) getSerialization() FieldSerialization { return &uuidField{} } 157 158 type Int64Field struct{} 159 type int64Field struct{ i int64 } 160 161 func (f *int64Field) Scan(src interface{}) (err error) { 162 switch tv := src.(type) { 163 case int: 164 f.i = int64(tv) 165 case int32: 166 f.i = int64(tv) 167 case int64: 168 f.i = tv 169 case uint: 170 f.i = int64(tv) 171 case uint32: 172 f.i = int64(tv) 173 case uint64: 174 f.i = int64(tv) 175 case string: 176 f.i, err = strconv.ParseInt(src.(string), 10, 64) 177 if err != nil { 178 return i18n.WrapError(context.Background(), err, i18n.MsgScanFailed, src, int64(0)) 179 } 180 default: 181 return i18n.NewError(context.Background(), i18n.MsgScanFailed, src, f.i) 182 } 183 return nil 184 } 185 func (f *int64Field) Value() (driver.Value, error) { return f.i, nil } 186 func (f *int64Field) String() string { return fmt.Sprintf("%d", f.i) } 187 func (f *Int64Field) getSerialization() FieldSerialization { return &int64Field{} } 188 189 type TimeField struct{} 190 type timeField struct{ t *fftypes.FFTime } 191 192 func (f *timeField) Scan(src interface{}) (err error) { 193 switch tv := src.(type) { 194 case int: 195 f.t = fftypes.UnixTime(int64(tv)) 196 case int64: 197 f.t = fftypes.UnixTime(tv) 198 case string: 199 f.t, err = fftypes.ParseString(tv) 200 return err 201 case fftypes.FFTime: 202 f.t = &tv 203 return nil 204 case *fftypes.FFTime: 205 f.t = tv 206 return nil 207 case nil: 208 f.t = nil 209 return nil 210 default: 211 return i18n.NewError(context.Background(), i18n.MsgScanFailed, src, f.t) 212 } 213 return nil 214 } 215 func (f *timeField) Value() (driver.Value, error) { 216 if f.t == nil { 217 return nil, nil 218 } 219 return f.t.UnixNano(), nil 220 } 221 func (f *timeField) String() string { return fmt.Sprintf("%v", f.t) } 222 func (f *TimeField) getSerialization() FieldSerialization { return &timeField{} } 223 224 type JSONField struct{} 225 type jsonField struct{ b []byte } 226 227 func (f *jsonField) Scan(src interface{}) (err error) { 228 switch tv := src.(type) { 229 case string: 230 f.b = []byte(tv) 231 case []byte: 232 f.b = tv 233 case fftypes.JSONObject: 234 f.b, err = json.Marshal(tv) 235 case nil: 236 f.b = nil 237 default: 238 return i18n.NewError(context.Background(), i18n.MsgScanFailed, src, f.b) 239 } 240 return err 241 } 242 func (f *jsonField) Value() (driver.Value, error) { return f.b, nil } 243 func (f *jsonField) String() string { return fmt.Sprintf("%s", f.b) } 244 func (f *JSONField) getSerialization() FieldSerialization { return &jsonField{} } 245 246 type FFNameArrayField struct{} 247 type ffNameArrayField struct{ na fftypes.FFNameArray } 248 249 func (f *ffNameArrayField) Scan(src interface{}) (err error) { 250 return f.na.Scan(src) 251 } 252 func (f *ffNameArrayField) Value() (driver.Value, error) { return f.na.String(), nil } 253 func (f *ffNameArrayField) String() string { return f.na.String() } 254 func (f *FFNameArrayField) getSerialization() FieldSerialization { return &ffNameArrayField{} } 255 256 type BoolField struct{} 257 type boolField struct{ b bool } 258 259 func (f *boolField) Scan(src interface{}) (err error) { 260 switch tv := src.(type) { 261 case int: 262 f.b = tv != 0 263 case int32: 264 f.b = tv != 0 265 case int64: 266 f.b = tv != 0 267 case uint: 268 f.b = tv != 0 269 case uint32: 270 f.b = tv != 0 271 case uint64: 272 f.b = tv != 0 273 case bool: 274 f.b = tv 275 case string: 276 f.b = strings.EqualFold(tv, "true") 277 case nil: 278 f.b = false 279 default: 280 return i18n.NewError(context.Background(), i18n.MsgScanFailed, src, f.b) 281 } 282 return nil 283 } 284 func (f *boolField) Value() (driver.Value, error) { return f.b, nil } 285 func (f *boolField) String() string { return fmt.Sprintf("%t", f.b) } 286 func (f *BoolField) getSerialization() FieldSerialization { return &boolField{} }