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  }