github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/internal/database/sqlcommon/nonce_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  	nonceColumns = []string{
    32  		"context",
    33  		"nonce",
    34  		"group_hash",
    35  		"topic",
    36  	}
    37  	nonceFilterTypeMap = map[string]string{
    38  		"group": "group_hash",
    39  	}
    40  )
    41  
    42  func (s *SQLCommon) UpsertNonceNext(ctx context.Context, nonce *fftypes.Nonce) (err error) {
    43  	ctx, tx, autoCommit, err := s.beginOrUseTx(ctx)
    44  	if err != nil {
    45  		return err
    46  	}
    47  	defer s.rollbackTx(ctx, tx, autoCommit)
    48  
    49  	existing := false
    50  	// Do a select within the transaction to detemine if the UUID already exists
    51  	nonceRows, err := s.queryTx(ctx, tx,
    52  		sq.Select("nonce", s.provider.SequenceField("")).
    53  			From("nonces").
    54  			Where(
    55  				sq.Eq{"context": nonce.Context}),
    56  	)
    57  	if err != nil {
    58  		return err
    59  	}
    60  	existing = nonceRows.Next()
    61  
    62  	if existing {
    63  		var existingNonce, sequence int64
    64  		err := nonceRows.Scan(&existingNonce, &sequence)
    65  		if err != nil {
    66  			nonceRows.Close()
    67  			return i18n.WrapError(ctx, err, i18n.MsgDBReadErr, "nonces")
    68  		}
    69  		nonce.Nonce = existingNonce + 1
    70  		nonceRows.Close()
    71  
    72  		// Update the nonce
    73  		if err = s.updateTx(ctx, tx,
    74  			sq.Update("nonces").
    75  				Set("nonce", nonce.Nonce).
    76  				Where(sq.Eq{s.provider.SequenceField(""): sequence}),
    77  		); err != nil {
    78  			return err
    79  		}
    80  	} else {
    81  		nonceRows.Close()
    82  
    83  		nonce.Nonce = 0
    84  		if _, err = s.insertTx(ctx, tx,
    85  			sq.Insert("nonces").
    86  				Columns(nonceColumns...).
    87  				Values(
    88  					nonce.Context,
    89  					nonce.Nonce,
    90  					nonce.Group,
    91  					nonce.Topic,
    92  				),
    93  		); err != nil {
    94  			return err
    95  		}
    96  	}
    97  
    98  	return s.commitTx(ctx, tx, autoCommit)
    99  }
   100  
   101  func (s *SQLCommon) nonceResult(ctx context.Context, row *sql.Rows) (*fftypes.Nonce, error) {
   102  	nonce := fftypes.Nonce{}
   103  	err := row.Scan(
   104  		&nonce.Context,
   105  		&nonce.Nonce,
   106  		&nonce.Group,
   107  		&nonce.Topic,
   108  	)
   109  	if err != nil {
   110  		return nil, i18n.WrapError(ctx, err, i18n.MsgDBReadErr, "nonces")
   111  	}
   112  	return &nonce, nil
   113  }
   114  
   115  func (s *SQLCommon) GetNonce(ctx context.Context, context *fftypes.Bytes32) (message *fftypes.Nonce, err error) {
   116  
   117  	rows, err := s.query(ctx,
   118  		sq.Select(nonceColumns...).
   119  			From("nonces").
   120  			Where(sq.Eq{"context": context}),
   121  	)
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  	defer rows.Close()
   126  
   127  	if !rows.Next() {
   128  		log.L(ctx).Debugf("Nonce '%s' not found", context)
   129  		return nil, nil
   130  	}
   131  
   132  	nonce, err := s.nonceResult(ctx, rows)
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  
   137  	return nonce, nil
   138  }
   139  
   140  func (s *SQLCommon) GetNonces(ctx context.Context, filter database.Filter) (message []*fftypes.Nonce, err error) {
   141  
   142  	query, err := s.filterSelect(ctx, "", sq.Select(nonceColumns...).From("nonces"), filter, nonceFilterTypeMap)
   143  	if err != nil {
   144  		return nil, err
   145  	}
   146  
   147  	rows, err := s.query(ctx, query)
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  	defer rows.Close()
   152  
   153  	nonce := []*fftypes.Nonce{}
   154  	for rows.Next() {
   155  		d, err := s.nonceResult(ctx, rows)
   156  		if err != nil {
   157  			return nil, err
   158  		}
   159  		nonce = append(nonce, d)
   160  	}
   161  
   162  	return nonce, err
   163  
   164  }
   165  
   166  func (s *SQLCommon) DeleteNonce(ctx context.Context, context *fftypes.Bytes32) (err error) {
   167  
   168  	ctx, tx, autoCommit, err := s.beginOrUseTx(ctx)
   169  	if err != nil {
   170  		return err
   171  	}
   172  	defer s.rollbackTx(ctx, tx, autoCommit)
   173  
   174  	err = s.deleteTx(ctx, tx, sq.Delete("nonces").Where(sq.Eq{
   175  		"context": context,
   176  	}))
   177  	if err != nil {
   178  		return err
   179  	}
   180  
   181  	return s.commitTx(ctx, tx, autoCommit)
   182  }