github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/internal/database/sqlcommon/offset_sql.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 sqlcommon 18 19 import ( 20 "context" 21 "database/sql" 22 23 sq "github.com/Masterminds/squirrel" 24 "github.com/kaleido-io/firefly/internal/i18n" 25 "github.com/kaleido-io/firefly/internal/log" 26 "github.com/kaleido-io/firefly/pkg/database" 27 "github.com/kaleido-io/firefly/pkg/fftypes" 28 ) 29 30 var ( 31 offsetColumns = []string{ 32 "id", 33 "otype", 34 "namespace", 35 "name", 36 "current", 37 } 38 offsetFilterTypeMap = map[string]string{ 39 "type": "otype", 40 } 41 ) 42 43 func (s *SQLCommon) UpsertOffset(ctx context.Context, offset *fftypes.Offset, allowExisting bool) (err error) { 44 ctx, tx, autoCommit, err := s.beginOrUseTx(ctx) 45 if err != nil { 46 return err 47 } 48 defer s.rollbackTx(ctx, tx, autoCommit) 49 50 existing := false 51 if allowExisting { 52 // Do a select within the transaction to detemine if the UUID already exists 53 offsetRows, err := s.queryTx(ctx, tx, 54 sq.Select("id"). 55 From("offsets"). 56 Where( 57 sq.Eq{"otype": offset.Type, 58 "namespace": offset.Namespace, 59 "name": offset.Name}), 60 ) 61 if err != nil { 62 return err 63 } 64 existing = offsetRows.Next() 65 if existing { 66 var id fftypes.UUID 67 _ = offsetRows.Scan(&id) 68 if offset.ID != nil { 69 if *offset.ID != id { 70 offsetRows.Close() 71 return database.IDMismatch 72 } 73 } 74 offset.ID = &id // Update on returned object 75 } 76 offsetRows.Close() 77 } 78 79 if existing { 80 81 // Update the offset 82 if err = s.updateTx(ctx, tx, 83 sq.Update("offsets"). 84 Set("otype", string(offset.Type)). 85 Set("namespace", offset.Namespace). 86 Set("name", offset.Name). 87 Set("current", offset.Current). 88 Where(sq.Eq{"id": offset.ID}), 89 ); err != nil { 90 return err 91 } 92 } else { 93 if _, err = s.insertTx(ctx, tx, 94 sq.Insert("offsets"). 95 Columns(offsetColumns...). 96 Values( 97 offset.ID, 98 string(offset.Type), 99 offset.Namespace, 100 offset.Name, 101 offset.Current, 102 ), 103 ); err != nil { 104 return err 105 } 106 } 107 108 return s.commitTx(ctx, tx, autoCommit) 109 } 110 111 func (s *SQLCommon) offsetResult(ctx context.Context, row *sql.Rows) (*fftypes.Offset, error) { 112 offset := fftypes.Offset{} 113 err := row.Scan( 114 &offset.ID, 115 &offset.Type, 116 &offset.Namespace, 117 &offset.Name, 118 &offset.Current, 119 ) 120 if err != nil { 121 return nil, i18n.WrapError(ctx, err, i18n.MsgDBReadErr, "offsets") 122 } 123 return &offset, nil 124 } 125 126 func (s *SQLCommon) GetOffset(ctx context.Context, t fftypes.OffsetType, ns, name string) (message *fftypes.Offset, err error) { 127 128 rows, err := s.query(ctx, 129 sq.Select(offsetColumns...). 130 From("offsets"). 131 Where(sq.Eq{"otype": t, 132 "namespace": ns, 133 "name": name}), 134 ) 135 if err != nil { 136 return nil, err 137 } 138 defer rows.Close() 139 140 if !rows.Next() { 141 log.L(ctx).Debugf("Offset '%s:%s:%s' not found", t, ns, name) 142 return nil, nil 143 } 144 145 offset, err := s.offsetResult(ctx, rows) 146 if err != nil { 147 return nil, err 148 } 149 150 return offset, nil 151 } 152 153 func (s *SQLCommon) GetOffsets(ctx context.Context, filter database.Filter) (message []*fftypes.Offset, err error) { 154 155 query, err := s.filterSelect(ctx, "", sq.Select(offsetColumns...).From("offsets"), filter, offsetFilterTypeMap) 156 if err != nil { 157 return nil, err 158 } 159 160 rows, err := s.query(ctx, query) 161 if err != nil { 162 return nil, err 163 } 164 defer rows.Close() 165 166 offset := []*fftypes.Offset{} 167 for rows.Next() { 168 d, err := s.offsetResult(ctx, rows) 169 if err != nil { 170 return nil, err 171 } 172 offset = append(offset, d) 173 } 174 175 return offset, err 176 177 } 178 179 func (s *SQLCommon) UpdateOffset(ctx context.Context, id *fftypes.UUID, update database.Update) (err error) { 180 181 ctx, tx, autoCommit, err := s.beginOrUseTx(ctx) 182 if err != nil { 183 return err 184 } 185 defer s.rollbackTx(ctx, tx, autoCommit) 186 187 query, err := s.buildUpdate(sq.Update("offsets"), update, offsetFilterTypeMap) 188 if err != nil { 189 return err 190 } 191 query = query.Where(sq.Eq{"id": id}) 192 193 err = s.updateTx(ctx, tx, query) 194 if err != nil { 195 return err 196 } 197 198 return s.commitTx(ctx, tx, autoCommit) 199 } 200 201 func (s *SQLCommon) DeleteOffset(ctx context.Context, t fftypes.OffsetType, ns, name string) (err error) { 202 203 ctx, tx, autoCommit, err := s.beginOrUseTx(ctx) 204 if err != nil { 205 return err 206 } 207 defer s.rollbackTx(ctx, tx, autoCommit) 208 209 err = s.deleteTx(ctx, tx, sq.Delete("offsets").Where(sq.Eq{ 210 "otype": t, 211 "namespace": ns, 212 "name": name, 213 })) 214 if err != nil { 215 return err 216 } 217 218 return s.commitTx(ctx, tx, autoCommit) 219 }