github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/internal/database/sqlcommon/batch_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  	batchColumns = []string{
    32  		"id",
    33  		"btype",
    34  		"namespace",
    35  		"author",
    36  		"group_hash",
    37  		"created",
    38  		"hash",
    39  		"payload",
    40  		"payload_ref",
    41  		"confirmed",
    42  		"tx_type",
    43  		"tx_id",
    44  	}
    45  	batchFilterTypeMap = map[string]string{
    46  		"type":             "btype",
    47  		"payloadref":       "payload_ref",
    48  		"transaction.type": "tx_type",
    49  		"transaction.id":   "tx_id",
    50  		"group":            "group_hash",
    51  	}
    52  )
    53  
    54  func (s *SQLCommon) UpsertBatch(ctx context.Context, batch *fftypes.Batch, allowExisting, allowHashUpdate bool) (err error) {
    55  	ctx, tx, autoCommit, err := s.beginOrUseTx(ctx)
    56  	if err != nil {
    57  		return err
    58  	}
    59  	defer s.rollbackTx(ctx, tx, autoCommit)
    60  
    61  	existing := false
    62  	if allowExisting {
    63  		// Do a select within the transaction to detemine if the UUID already exists
    64  		batchRows, err := s.queryTx(ctx, tx,
    65  			sq.Select("hash").
    66  				From("batches").
    67  				Where(sq.Eq{"id": batch.ID}),
    68  		)
    69  		if err != nil {
    70  			return err
    71  		}
    72  
    73  		existing = batchRows.Next()
    74  		if existing && !allowHashUpdate {
    75  			var hash *fftypes.Bytes32
    76  			_ = batchRows.Scan(&hash)
    77  			if !fftypes.SafeHashCompare(hash, batch.Hash) {
    78  				batchRows.Close()
    79  				log.L(ctx).Errorf("Existing=%s New=%s", hash, batch.Hash)
    80  				return database.HashMismatch
    81  			}
    82  		}
    83  		batchRows.Close()
    84  	}
    85  
    86  	if existing {
    87  
    88  		// Update the batch
    89  		if err = s.updateTx(ctx, tx,
    90  			sq.Update("batches").
    91  				Set("btype", string(batch.Type)).
    92  				Set("namespace", batch.Namespace).
    93  				Set("author", batch.Author).
    94  				Set("group_hash", batch.Group).
    95  				Set("created", batch.Created).
    96  				Set("hash", batch.Hash).
    97  				Set("payload", batch.Payload).
    98  				Set("payload_ref", batch.PayloadRef).
    99  				Set("confirmed", batch.Confirmed).
   100  				Set("tx_type", batch.Payload.TX.Type).
   101  				Set("tx_id", batch.Payload.TX.ID).
   102  				Where(sq.Eq{"id": batch.ID}),
   103  		); err != nil {
   104  			return err
   105  		}
   106  	} else {
   107  
   108  		if _, err = s.insertTx(ctx, tx,
   109  			sq.Insert("batches").
   110  				Columns(batchColumns...).
   111  				Values(
   112  					batch.ID,
   113  					string(batch.Type),
   114  					batch.Namespace,
   115  					batch.Author,
   116  					batch.Group,
   117  					batch.Created,
   118  					batch.Hash,
   119  					batch.Payload,
   120  					batch.PayloadRef,
   121  					batch.Confirmed,
   122  					batch.Payload.TX.Type,
   123  					batch.Payload.TX.ID,
   124  				),
   125  		); err != nil {
   126  			return err
   127  		}
   128  	}
   129  
   130  	return s.commitTx(ctx, tx, autoCommit)
   131  }
   132  
   133  func (s *SQLCommon) batchResult(ctx context.Context, row *sql.Rows) (*fftypes.Batch, error) {
   134  	var batch fftypes.Batch
   135  	err := row.Scan(
   136  		&batch.ID,
   137  		&batch.Type,
   138  		&batch.Namespace,
   139  		&batch.Author,
   140  		&batch.Group,
   141  		&batch.Created,
   142  		&batch.Hash,
   143  		&batch.Payload,
   144  		&batch.PayloadRef,
   145  		&batch.Confirmed,
   146  		&batch.Payload.TX.Type,
   147  		&batch.Payload.TX.ID,
   148  	)
   149  	if err != nil {
   150  		return nil, i18n.WrapError(ctx, err, i18n.MsgDBReadErr, "batches")
   151  	}
   152  	return &batch, nil
   153  }
   154  
   155  func (s *SQLCommon) GetBatchByID(ctx context.Context, id *fftypes.UUID) (message *fftypes.Batch, err error) {
   156  
   157  	rows, err := s.query(ctx,
   158  		sq.Select(batchColumns...).
   159  			From("batches").
   160  			Where(sq.Eq{"id": id}),
   161  	)
   162  	if err != nil {
   163  		return nil, err
   164  	}
   165  	defer rows.Close()
   166  
   167  	if !rows.Next() {
   168  		log.L(ctx).Debugf("Batch '%s' not found", id)
   169  		return nil, nil
   170  	}
   171  
   172  	batch, err := s.batchResult(ctx, rows)
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  
   177  	return batch, nil
   178  }
   179  
   180  func (s *SQLCommon) GetBatches(ctx context.Context, filter database.Filter) (message []*fftypes.Batch, err error) {
   181  
   182  	query, err := s.filterSelect(ctx, "", sq.Select(batchColumns...).From("batches"), filter, batchFilterTypeMap)
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  
   187  	rows, err := s.query(ctx, query)
   188  	if err != nil {
   189  		return nil, err
   190  	}
   191  	defer rows.Close()
   192  
   193  	batches := []*fftypes.Batch{}
   194  	for rows.Next() {
   195  		batch, err := s.batchResult(ctx, rows)
   196  		if err != nil {
   197  			return nil, err
   198  		}
   199  		batches = append(batches, batch)
   200  	}
   201  
   202  	return batches, err
   203  
   204  }
   205  
   206  func (s *SQLCommon) UpdateBatch(ctx context.Context, id *fftypes.UUID, update database.Update) (err error) {
   207  
   208  	ctx, tx, autoCommit, err := s.beginOrUseTx(ctx)
   209  	if err != nil {
   210  		return err
   211  	}
   212  	defer s.rollbackTx(ctx, tx, autoCommit)
   213  
   214  	query, err := s.buildUpdate(sq.Update("batches"), update, batchFilterTypeMap)
   215  	if err != nil {
   216  		return err
   217  	}
   218  	query = query.Where(sq.Eq{"id": id})
   219  
   220  	err = s.updateTx(ctx, tx, query)
   221  	if err != nil {
   222  		return err
   223  	}
   224  
   225  	return s.commitTx(ctx, tx, autoCommit)
   226  }