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  }