github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/internal/database/sqlcommon/subscription_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  	subscriptionColumns = []string{
    33  		"id",
    34  		"namespace",
    35  		"name",
    36  		"transport",
    37  		"filter_events",
    38  		"filter_topics",
    39  		"filter_tag",
    40  		"filter_group",
    41  		"options",
    42  		"created",
    43  	}
    44  	subscriptionFilterTypeMap = map[string]string{
    45  		"filter.events": "filter_events",
    46  		"filter.topics": "filter_topics",
    47  		"filter.tag":    "filter_tag",
    48  		"filter.group":  "filter_group",
    49  	}
    50  )
    51  
    52  func (s *SQLCommon) UpsertSubscription(ctx context.Context, subscription *fftypes.Subscription, allowExisting bool) (err error) {
    53  	ctx, tx, autoCommit, err := s.beginOrUseTx(ctx)
    54  	if err != nil {
    55  		return err
    56  	}
    57  	defer s.rollbackTx(ctx, tx, autoCommit)
    58  
    59  	existing := false
    60  	if allowExisting {
    61  		// Do a select within the transaction to detemine if the UUID already exists
    62  		subscriptionRows, err := s.queryTx(ctx, tx,
    63  			sq.Select("id").
    64  				From("subscriptions").
    65  				Where(sq.Eq{
    66  					"namespace": subscription.Namespace,
    67  					"name":      subscription.Name,
    68  				}),
    69  		)
    70  		if err != nil {
    71  			return err
    72  		}
    73  
    74  		existing = subscriptionRows.Next()
    75  		if existing {
    76  			var id fftypes.UUID
    77  			_ = subscriptionRows.Scan(&id)
    78  			if subscription.ID != nil {
    79  				if *subscription.ID != id {
    80  					subscriptionRows.Close()
    81  					return database.IDMismatch
    82  				}
    83  			}
    84  			subscription.ID = &id // Update on returned object
    85  		}
    86  		subscriptionRows.Close()
    87  	}
    88  
    89  	if existing {
    90  		// Update the subscription
    91  		if err = s.updateTx(ctx, tx,
    92  			sq.Update("subscriptions").
    93  				// Note we do not update ID
    94  				Set("namespace", subscription.Namespace).
    95  				Set("name", subscription.Name).
    96  				Set("transport", subscription.Transport).
    97  				Set("filter_events", subscription.Filter.Events).
    98  				Set("filter_topics", subscription.Filter.Topics).
    99  				Set("filter_tag", subscription.Filter.Tag).
   100  				Set("filter_group", subscription.Filter.Group).
   101  				Set("options", subscription.Options).
   102  				Set("created", subscription.Created).
   103  				Where(sq.Eq{
   104  					"namespace": subscription.Namespace,
   105  					"name":      subscription.Name,
   106  				}),
   107  		); err != nil {
   108  			return err
   109  		}
   110  	} else {
   111  		if subscription.ID == nil {
   112  			subscription.ID = fftypes.NewUUID()
   113  		}
   114  
   115  		if _, err = s.insertTx(ctx, tx,
   116  			sq.Insert("subscriptions").
   117  				Columns(subscriptionColumns...).
   118  				Values(
   119  					subscription.ID,
   120  					subscription.Namespace,
   121  					subscription.Name,
   122  					subscription.Transport,
   123  					subscription.Filter.Events,
   124  					subscription.Filter.Topics,
   125  					subscription.Filter.Tag,
   126  					subscription.Filter.Group,
   127  					subscription.Options,
   128  					subscription.Created,
   129  				),
   130  		); err != nil {
   131  			return err
   132  		}
   133  
   134  		s.postCommitEvent(tx, func() {
   135  			s.callbacks.SubscriptionCreated(subscription.ID)
   136  		})
   137  
   138  	}
   139  
   140  	return s.commitTx(ctx, tx, autoCommit)
   141  }
   142  
   143  func (s *SQLCommon) subscriptionResult(ctx context.Context, row *sql.Rows) (*fftypes.Subscription, error) {
   144  	subscription := fftypes.Subscription{}
   145  	err := row.Scan(
   146  		&subscription.ID,
   147  		&subscription.Namespace,
   148  		&subscription.Name,
   149  		&subscription.Transport,
   150  		&subscription.Filter.Events,
   151  		&subscription.Filter.Topics,
   152  		&subscription.Filter.Tag,
   153  		&subscription.Filter.Group,
   154  		&subscription.Options,
   155  		&subscription.Created,
   156  	)
   157  	if err != nil {
   158  		return nil, i18n.WrapError(ctx, err, i18n.MsgDBReadErr, "subscriptions")
   159  	}
   160  	return &subscription, nil
   161  }
   162  
   163  func (s *SQLCommon) getSubscriptionEq(ctx context.Context, eq sq.Eq, textName string) (message *fftypes.Subscription, err error) {
   164  
   165  	rows, err := s.query(ctx,
   166  		sq.Select(subscriptionColumns...).
   167  			From("subscriptions").
   168  			Where(eq),
   169  	)
   170  	if err != nil {
   171  		return nil, err
   172  	}
   173  	defer rows.Close()
   174  
   175  	if !rows.Next() {
   176  		log.L(ctx).Debugf("Subscription '%s' not found", textName)
   177  		return nil, nil
   178  	}
   179  
   180  	subscription, err := s.subscriptionResult(ctx, rows)
   181  	if err != nil {
   182  		return nil, err
   183  	}
   184  
   185  	return subscription, nil
   186  }
   187  
   188  func (s *SQLCommon) GetSubscriptionByID(ctx context.Context, id *fftypes.UUID) (message *fftypes.Subscription, err error) {
   189  	return s.getSubscriptionEq(ctx, sq.Eq{"id": id}, id.String())
   190  }
   191  
   192  func (s *SQLCommon) GetSubscriptionByName(ctx context.Context, ns, name string) (message *fftypes.Subscription, err error) {
   193  	return s.getSubscriptionEq(ctx, sq.Eq{"namespace": ns, "name": name}, fmt.Sprintf("%s:%s", ns, name))
   194  }
   195  
   196  func (s *SQLCommon) GetSubscriptions(ctx context.Context, filter database.Filter) (message []*fftypes.Subscription, err error) {
   197  
   198  	query, err := s.filterSelect(ctx, "", sq.Select(subscriptionColumns...).From("subscriptions"), filter, subscriptionFilterTypeMap)
   199  	if err != nil {
   200  		return nil, err
   201  	}
   202  
   203  	rows, err := s.query(ctx, query)
   204  	if err != nil {
   205  		return nil, err
   206  	}
   207  	defer rows.Close()
   208  
   209  	subscription := []*fftypes.Subscription{}
   210  	for rows.Next() {
   211  		d, err := s.subscriptionResult(ctx, rows)
   212  		if err != nil {
   213  			return nil, err
   214  		}
   215  		subscription = append(subscription, d)
   216  	}
   217  
   218  	return subscription, err
   219  
   220  }
   221  
   222  func (s *SQLCommon) UpdateSubscription(ctx context.Context, namespace, name string, update database.Update) (err error) {
   223  
   224  	ctx, tx, autoCommit, err := s.beginOrUseTx(ctx)
   225  	if err != nil {
   226  		return err
   227  	}
   228  	defer s.rollbackTx(ctx, tx, autoCommit)
   229  
   230  	query, err := s.buildUpdate(sq.Update("subscriptions"), update, subscriptionFilterTypeMap)
   231  	if err != nil {
   232  		return err
   233  	}
   234  	query = query.Where(sq.Eq{
   235  		"namespace": namespace,
   236  		"name":      name,
   237  	})
   238  
   239  	err = s.updateTx(ctx, tx, query)
   240  	if err != nil {
   241  		return err
   242  	}
   243  
   244  	return s.commitTx(ctx, tx, autoCommit)
   245  }
   246  
   247  func (s *SQLCommon) DeleteSubscriptionByID(ctx context.Context, id *fftypes.UUID) (err error) {
   248  
   249  	ctx, tx, autoCommit, err := s.beginOrUseTx(ctx)
   250  	if err != nil {
   251  		return err
   252  	}
   253  	defer s.rollbackTx(ctx, tx, autoCommit)
   254  
   255  	err = s.deleteTx(ctx, tx, sq.Delete("subscriptions").Where(sq.Eq{
   256  		"id": id,
   257  	}))
   258  	if err != nil {
   259  		return err
   260  	}
   261  
   262  	s.postCommitEvent(tx, func() {
   263  		s.callbacks.SubscriptionDeleted(id)
   264  	})
   265  
   266  	return s.commitTx(ctx, tx, autoCommit)
   267  }