github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/pkg/database/update.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 "fmt" 22 "strings" 23 24 "github.com/kaleido-io/firefly/internal/i18n" 25 ) 26 27 // UpdateBuilder is the output of the builder 28 type UpdateBuilder interface { 29 // Set starts creation of a set operation 30 Set(field string, value interface{}) Update 31 32 // S starts an update that doesn't have any fields 33 S() Update 34 35 // Fields returns the available fields on the update 36 Fields() []string 37 } 38 39 type Update interface { 40 // Set adds a set condition to the update 41 Set(field string, value interface{}) Update 42 43 // IsEmpty 44 IsEmpty() bool 45 46 // Finalize completes the update, and for the plugin to validated output structure to convert 47 Finalize() (*UpdateInfo, error) 48 } 49 50 // UpdateFactory creates a update builder in the given context, and contains the rules on 51 // which fields can be used by the builder (and how they are serialized) 52 type UpdateFactory interface { 53 New(ctx context.Context) UpdateBuilder 54 } 55 56 // SetOperation is an individual update action to perform 57 type SetOperation struct { 58 Field string 59 Value FieldSerialization 60 } 61 62 // UpdateInfo is the structure returned by Finalize to the plugin, to serialize this uilter 63 // into the underlying database mechanism's uilter language 64 type UpdateInfo struct { 65 SetOperations []*SetOperation 66 } 67 68 type setOperation struct { 69 field string 70 value interface{} 71 } 72 73 type updateBuilder struct { 74 ctx context.Context 75 queryFields queryFields 76 } 77 78 func (ub *updateBuilder) Fields() []string { 79 keys := make([]string, len(ub.queryFields)) 80 i := 0 81 for k := range ub.queryFields { 82 keys[i] = k 83 i++ 84 } 85 return keys 86 } 87 88 func (ub *updateBuilder) Set(field string, value interface{}) Update { 89 return &setUpdate{ 90 ub: ub, 91 setOperations: []*setOperation{{field, value}}, 92 } 93 } 94 95 func (ub *updateBuilder) S() Update { 96 return &setUpdate{ 97 ub: ub, 98 setOperations: []*setOperation{}, 99 } 100 } 101 102 type setUpdate struct { 103 ub *updateBuilder 104 setOperations []*setOperation 105 } 106 107 func (u *setUpdate) IsEmpty() bool { 108 return len(u.setOperations) == 0 109 } 110 111 func (u *setUpdate) Set(field string, value interface{}) Update { 112 u.setOperations = append(u.setOperations, &setOperation{field, value}) 113 return u 114 } 115 116 func (u *UpdateInfo) String() string { 117 var buf strings.Builder 118 for i, si := range u.SetOperations { 119 if i > 0 { 120 buf.WriteString(", ") 121 } 122 buf.WriteString(fmt.Sprintf("%s=%s", si.Field, valueString(si.Value))) 123 } 124 return buf.String() 125 } 126 127 func (u *setUpdate) Finalize() (*UpdateInfo, error) { 128 ui := &UpdateInfo{ 129 SetOperations: make([]*SetOperation, len(u.setOperations)), 130 } 131 for i, si := range u.setOperations { 132 name := strings.ToLower(si.field) 133 field, ok := u.ub.queryFields[name] 134 if !ok { 135 return nil, i18n.NewError(u.ub.ctx, i18n.MsgInvalidFilterField, name) 136 } 137 value := field.getSerialization() 138 if err := value.Scan(si.value); err != nil { 139 return nil, i18n.WrapError(u.ub.ctx, err, i18n.MsgInvalidValueForFilterField, name) 140 } 141 ui.SetOperations[i] = &SetOperation{ 142 Field: name, 143 Value: value, 144 } 145 } 146 return ui, nil 147 }