github.com/RevenueMonster/sqlike@v1.0.6/examples/transaction.go (about)

     1  package examples
     2  
     3  import (
     4  	"context"
     5  	"database/sql"
     6  	"errors"
     7  	"math/rand"
     8  	"testing"
     9  	"time"
    10  
    11  	"cloud.google.com/go/civil"
    12  	uuid "github.com/google/uuid"
    13  
    14  	"github.com/RevenueMonster/sqlike/sql/expr"
    15  	"github.com/RevenueMonster/sqlike/sqlike"
    16  	"github.com/RevenueMonster/sqlike/sqlike/actions"
    17  	"github.com/RevenueMonster/sqlike/sqlike/options"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  type user struct {
    22  	ID   int `sqlike:"$Key"`
    23  	Name string
    24  }
    25  
    26  // TransactionExamples :
    27  func TransactionExamples(ctx context.Context, t *testing.T, db *sqlike.Database) {
    28  	var (
    29  		uid      uuid.UUID
    30  		ns       normalStruct
    31  		result   sql.Result
    32  		affected int64
    33  		err      error
    34  		tx       *sqlike.Transaction
    35  	)
    36  
    37  	// Commit Transaction
    38  	{
    39  		uid, _ = uuid.Parse(`be72fc34-917b-11e9-af91-6c96cfd87a51`)
    40  		now := time.Now()
    41  
    42  		ns = normalStruct{}
    43  		ns.ID = uid
    44  		ns.Date = civil.DateOf(now)
    45  		ns.DateTime = now
    46  		ns.Timestamp = now
    47  		ns.CreatedAt = now
    48  		ns.UpdatedAt = now
    49  		tx, err = db.BeginTransaction(ctx)
    50  		require.NoError(t, err)
    51  		result, err = tx.Table("NormalStruct").InsertOne(ctx, &ns)
    52  		require.NoError(t, err)
    53  		affected, err = result.RowsAffected()
    54  		require.NoError(t, err)
    55  		require.Equal(t, int64(1), affected)
    56  
    57  		err = tx.CommitTransaction()
    58  		require.NoError(t, err)
    59  	}
    60  
    61  	// Abort Transaction
    62  	{
    63  		uid, _ = uuid.Parse(`be7191c8-917b-11e9-af91-6c96cfd87a51`)
    64  		now := time.Now()
    65  
    66  		ns = normalStruct{}
    67  		ns.ID = uid
    68  		ns.Date = civil.DateOf(now)
    69  		ns.DateTime = now
    70  		ns.Timestamp = now
    71  		ns.CreatedAt = now
    72  		ns.UpdatedAt = now
    73  		tx, err = db.BeginTransaction(ctx)
    74  		require.NoError(t, err)
    75  		result, err = tx.Table("NormalStruct").InsertOne(ctx, &ns)
    76  		require.NoError(t, err)
    77  		affected, err = result.RowsAffected()
    78  		require.NoError(t, err)
    79  		require.Equal(t, int64(1), affected)
    80  
    81  		err = tx.RollbackTransaction()
    82  		require.NoError(t, err)
    83  
    84  		ns = normalStruct{}
    85  		err = db.Table("NormalStruct").FindOne(
    86  			ctx,
    87  			actions.FindOne().
    88  				Where(
    89  					expr.Equal("$Key", uid),
    90  				),
    91  		).Decode(&ns)
    92  		require.Equal(t, sql.ErrNoRows, err)
    93  	}
    94  
    95  	// RunInTransaction
    96  	{
    97  		err = db.RunInTransaction(ctx,
    98  			func(sess sqlike.SessionContext) error {
    99  				uid, _ = uuid.Parse(`4ab3898c-9192-11e9-b500-6c96cfd87a51`)
   100  				now := time.Now()
   101  
   102  				ns = normalStruct{}
   103  				ns.ID = uid
   104  				ns.Date = civil.DateOf(now)
   105  				ns.DateTime = now
   106  				ns.Timestamp = now
   107  				ns.CreatedAt = now
   108  				ns.UpdatedAt = now
   109  				result, err := sess.Table("NormalStruct").InsertOne(sess, &ns)
   110  				if err != nil {
   111  					return err
   112  				}
   113  
   114  				ns.Int = 888
   115  				if _, err := sess.Table("NormalStruct").
   116  					UpdateOne(
   117  						sess,
   118  						actions.UpdateOne().
   119  							Where(
   120  								expr.Equal("$Key", ns.ID),
   121  							).
   122  							Set(
   123  								expr.ColumnValue("Int", ns.Int),
   124  							),
   125  					); err != nil {
   126  					return err
   127  				}
   128  
   129  				affected, err := result.RowsAffected()
   130  				if err != nil {
   131  					return err
   132  				}
   133  				if affected < 1 {
   134  					return errors.New("no result affected")
   135  				}
   136  				return nil
   137  			})
   138  		require.NoError(t, err)
   139  	}
   140  
   141  	// Timeout transaction
   142  	{
   143  		uid, _ = uuid.Parse(`5eb3f5c6-bfdb-11e9-88c7-6c96cfd87a51`)
   144  		now := time.Now()
   145  		err = db.RunInTransaction(
   146  			ctx, func(sess sqlike.SessionContext) error {
   147  				ns = normalStruct{}
   148  				ns.ID = uid
   149  				ns.Date = civil.DateOf(now)
   150  				ns.DateTime = now
   151  				ns.Timestamp = now
   152  				ns.CreatedAt = now
   153  				ns.UpdatedAt = now
   154  				_, err := sess.Table("NormalStruct").
   155  					InsertOne(
   156  						sess,
   157  						&ns, options.InsertOne().SetDebug(true),
   158  					)
   159  				if err != nil {
   160  					return err
   161  				}
   162  				time.Sleep(5 * time.Second)
   163  				return nil
   164  			}, options.Transaction().SetTimeOut(3*time.Second))
   165  		require.Equal(t, sql.ErrTxDone, err)
   166  
   167  		rslt := normalStruct{}
   168  		err = db.Table("NormalStruct").FindOne(
   169  			ctx,
   170  			actions.FindOne().
   171  				Where(
   172  					expr.Equal("$Key", uid),
   173  				),
   174  			options.FindOne().SetDebug(true),
   175  		).Decode(&rslt)
   176  		require.Error(t, err)
   177  		require.Equal(t, normalStruct{}, rslt)
   178  	}
   179  
   180  	// Lock record using transaction
   181  	{
   182  		err = db.RunInTransaction(
   183  			ctx, func(sess sqlike.SessionContext) error {
   184  				nss := []normalStruct{}
   185  				result, err := sess.Table("NormalStruct").
   186  					Find(
   187  						sess,
   188  						nil, options.Find().
   189  							SetLockMode(options.LockForUpdate).
   190  							SetDebug(true),
   191  					)
   192  				if err != nil {
   193  					return err
   194  				}
   195  				if err := result.All(&nss); err != nil {
   196  					return err
   197  				}
   198  				time.Sleep(1 * time.Second)
   199  				return nil
   200  			})
   201  		require.NoError(t, err)
   202  	}
   203  
   204  	err = db.Table("UserAddress").DropIfExists(ctx)
   205  	require.NoError(t, err)
   206  
   207  	table := db.Table("user")
   208  	err = table.DropIfExists(ctx)
   209  	require.NoError(t, err)
   210  	table.MustMigrate(ctx, new(user))
   211  
   212  	// Commit Transaction
   213  	{
   214  		data := &user{ID: rand.Intn(10000), Name: "Oska"}
   215  		trx, _ := db.BeginTransaction(ctx)
   216  		_, err = trx.Table("user").InsertOne(ctx, data)
   217  		require.NoError(t, err)
   218  
   219  		err = trx.Table("user").FindOne(
   220  			ctx,
   221  			actions.FindOne().
   222  				Where(
   223  					expr.Equal("$Key", data.ID),
   224  				),
   225  		).Decode(&user{})
   226  		require.NoError(t, err)
   227  
   228  		err = db.Table("user").FindOne(
   229  			ctx,
   230  			actions.FindOne().
   231  				Where(
   232  					expr.Equal("$Key", data.ID),
   233  				),
   234  		).Decode(&user{})
   235  		require.Error(t, err)
   236  
   237  		err = trx.CommitTransaction()
   238  		require.NoError(t, err)
   239  
   240  		err = db.Table("user").FindOne(
   241  			ctx,
   242  			actions.FindOne().
   243  				Where(
   244  					expr.Equal("$Key", data.ID),
   245  				),
   246  		).Decode(&user{})
   247  		require.NoError(t, err)
   248  
   249  		// Remove tested data
   250  		err = db.Table("user").DestroyOne(ctx, data)
   251  		require.NoError(t, err)
   252  	}
   253  
   254  	// Rollback Transaction
   255  	{
   256  		data := &user{ID: 1234, Name: "Oska"}
   257  		trx, _ := db.BeginTransaction(ctx)
   258  		_, err = trx.Table("user").InsertOne(ctx, data)
   259  		require.NoError(t, err)
   260  
   261  		err = trx.Table("user").FindOne(
   262  			ctx,
   263  			actions.FindOne().
   264  				Where(
   265  					expr.Equal("$Key", data.ID),
   266  				),
   267  		).Decode(&user{})
   268  		require.NoError(t, err)
   269  
   270  		err = db.Table("user").FindOne(
   271  			ctx,
   272  			actions.FindOne().
   273  				Where(
   274  					expr.Equal("$Key", data.ID),
   275  				),
   276  		).Decode(&user{})
   277  		require.Error(t, err)
   278  
   279  		err = trx.RollbackTransaction()
   280  		require.NoError(t, err)
   281  
   282  		err = db.Table("user").FindOne(
   283  			ctx,
   284  			actions.FindOne().
   285  				Where(
   286  					expr.Equal("$Key", data.ID),
   287  				),
   288  		).Decode(&user{})
   289  		require.Error(t, err)
   290  	}
   291  }