...

Source file src/github.com/DATA-DOG/go-sqlmock/examples/orders/orders.go

Documentation: github.com/DATA-DOG/go-sqlmock/examples/orders

     1  package main
     2  
     3  import (
     4  	"database/sql"
     5  	"fmt"
     6  	"log"
     7  
     8  	"github.com/kisielk/sqlstruct"
     9  )
    10  
    11  const ORDER_PENDING = 0
    12  const ORDER_CANCELLED = 1
    13  
    14  type User struct {
    15  	Id       int     `sql:"id"`
    16  	Username string  `sql:"username"`
    17  	Balance  float64 `sql:"balance"`
    18  }
    19  
    20  type Order struct {
    21  	Id          int     `sql:"id"`
    22  	Value       float64 `sql:"value"`
    23  	ReservedFee float64 `sql:"reserved_fee"`
    24  	Status      int     `sql:"status"`
    25  }
    26  
    27  func cancelOrder(id int, db *sql.DB) (err error) {
    28  	tx, err := db.Begin()
    29  	if err != nil {
    30  		return
    31  	}
    32  
    33  	var order Order
    34  	var user User
    35  	sql := fmt.Sprintf(`
    36  SELECT %s, %s
    37  FROM orders AS o
    38  INNER JOIN users AS u ON o.buyer_id = u.id
    39  WHERE o.id = ?
    40  FOR UPDATE`,
    41  		sqlstruct.ColumnsAliased(order, "o"),
    42  		sqlstruct.ColumnsAliased(user, "u"))
    43  
    44  	// fetch order to cancel
    45  	rows, err := tx.Query(sql, id)
    46  	if err != nil {
    47  		tx.Rollback()
    48  		return
    49  	}
    50  
    51  	defer rows.Close()
    52  	// no rows, nothing to do
    53  	if !rows.Next() {
    54  		tx.Rollback()
    55  		return
    56  	}
    57  
    58  	// read order
    59  	err = sqlstruct.ScanAliased(&order, rows, "o")
    60  	if err != nil {
    61  		tx.Rollback()
    62  		return
    63  	}
    64  
    65  	// ensure order status
    66  	if order.Status != ORDER_PENDING {
    67  		tx.Rollback()
    68  		return
    69  	}
    70  
    71  	// read user
    72  	err = sqlstruct.ScanAliased(&user, rows, "u")
    73  	if err != nil {
    74  		tx.Rollback()
    75  		return
    76  	}
    77  	rows.Close() // manually close before other prepared statements
    78  
    79  	// refund order value
    80  	sql = "UPDATE users SET balance = balance + ? WHERE id = ?"
    81  	refundStmt, err := tx.Prepare(sql)
    82  	if err != nil {
    83  		tx.Rollback()
    84  		return
    85  	}
    86  	defer refundStmt.Close()
    87  	_, err = refundStmt.Exec(order.Value+order.ReservedFee, user.Id)
    88  	if err != nil {
    89  		tx.Rollback()
    90  		return
    91  	}
    92  
    93  	// update order status
    94  	order.Status = ORDER_CANCELLED
    95  	sql = "UPDATE orders SET status = ?, updated = NOW() WHERE id = ?"
    96  	orderUpdStmt, err := tx.Prepare(sql)
    97  	if err != nil {
    98  		tx.Rollback()
    99  		return
   100  	}
   101  	defer orderUpdStmt.Close()
   102  	_, err = orderUpdStmt.Exec(order.Status, order.Id)
   103  	if err != nil {
   104  		tx.Rollback()
   105  		return
   106  	}
   107  	return tx.Commit()
   108  }
   109  
   110  func main() {
   111  	// @NOTE: the real connection is not required for tests
   112  	db, err := sql.Open("mysql", "root:@/orders")
   113  	if err != nil {
   114  		log.Fatal(err)
   115  	}
   116  	defer db.Close()
   117  	err = cancelOrder(1, db)
   118  	if err != nil {
   119  		log.Fatal(err)
   120  	}
   121  }
   122  

View as plain text