1 package storage 2 3 import "context" 4 5 // A storage provider that has support for transactions should implement this interface to ensure atomicity for certain flows 6 // that require transactional semantics. Fosite will call these methods (when atomicity is required) if and only if the storage 7 // provider has implemented `Transactional`. It is expected that the storage provider will examine context for an existing transaction 8 // each time a database operation is to be performed. 9 // 10 // An implementation of `BeginTX` should attempt to initiate a new transaction and store that under a unique key 11 // in the context that can be accessible by `Commit` and `Rollback`. The "transactional aware" context will then be 12 // returned for further propagation, eventually to be consumed by `Commit` or `Rollback` to finish the transaction. 13 // 14 // Implementations for `Commit` & `Rollback` should look for the transaction object inside the supplied context using the same 15 // key used by `BeginTX`. If these methods have been called, it is expected that a txn object should be available in the provided 16 // context. 17 type Transactional interface { 18 BeginTX(ctx context.Context) (context.Context, error) 19 Commit(ctx context.Context) error 20 Rollback(ctx context.Context) error 21 } 22 23 // MaybeBeginTx is a helper function that can be used to initiate a transaction if the supplied storage 24 // implements the `Transactional` interface. 25 func MaybeBeginTx(ctx context.Context, storage interface{}) (context.Context, error) { 26 // the type assertion checks whether the dynamic type of `storage` implements `Transactional` 27 txnStorage, transactional := storage.(Transactional) 28 if transactional { 29 return txnStorage.BeginTX(ctx) 30 } else { 31 return ctx, nil 32 } 33 } 34 35 // MaybeCommitTx is a helper function that can be used to commit a transaction if the supplied storage 36 // implements the `Transactional` interface. 37 func MaybeCommitTx(ctx context.Context, storage interface{}) error { 38 txnStorage, transactional := storage.(Transactional) 39 if transactional { 40 return txnStorage.Commit(ctx) 41 } else { 42 return nil 43 } 44 } 45 46 // MaybeRollbackTx is a helper function that can be used to rollback a transaction if the supplied storage 47 // implements the `Transactional` interface. 48 func MaybeRollbackTx(ctx context.Context, storage interface{}) error { 49 txnStorage, transactional := storage.(Transactional) 50 if transactional { 51 return txnStorage.Rollback(ctx) 52 } else { 53 return nil 54 } 55 } 56