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