github.com/wawandco/ox@v0.13.6-0.20230809142027-913b3d837f2a/pkg/buffalotools/database_middleware.go (about) 1 package buffalotools 2 3 import ( 4 "errors" 5 "net/http" 6 "time" 7 8 "github.com/gobuffalo/buffalo" 9 "github.com/gobuffalo/pop/v6" 10 ) 11 12 var errNonSuccess = errors.New("non success status code") 13 14 // DatabaseMiddleware returns a database connection provider middleware 15 // that will add the db into the `tx` context variable, in case its a 16 // PUT/POST/DELETE/PATCH method, it will wrap the 17 // handler in a transaction, otherwise it will just 18 // add the connection in the context. 19 // 20 // Provided middleware can also consider a seccond read only replica 21 // database connection (rodb) that will be used on idempotent operations if present. 22 func DatabaseMiddleware(db, rodb *pop.Connection) buffalo.MiddlewareFunc { 23 return func(h buffalo.Handler) buffalo.Handler { 24 return func(c buffalo.Context) error { 25 26 // Setting the context on the DB. 27 dbc := db.WithContext(c) 28 29 switch c.Request().Method { 30 default: 31 // If the passed read only db (rodb) is different than nil it should use it. 32 // As this block is for read only operations. 33 if rodb != nil { 34 dbc = rodb.WithContext(c) 35 } 36 37 c.Set("tx", dbc) 38 39 return h(c) 40 case http.MethodPost, http.MethodPut, http.MethodDelete, http.MethodPatch: 41 couldBeDBorYourErr := dbc.Transaction(func(tx *pop.Connection) error { 42 // setup logging 43 start := tx.Elapsed 44 defer func() { 45 finished := tx.Elapsed 46 elapsed := time.Duration(finished - start) 47 c.LogField("db", elapsed) 48 }() 49 50 // add the transaction to the context 51 c.Set("tx", tx) 52 53 // call the next handler; if it errors stop and return the error 54 if yourError := h(c); yourError != nil { 55 return yourError 56 } 57 58 // check the response status code. if the code is NOT 200..399 59 // then it is considered "NOT SUCCESSFUL" and an error will be returned 60 if res, ok := c.Response().(*buffalo.Response); ok { 61 if res.Status < 200 || res.Status >= 400 { 62 return errNonSuccess 63 } 64 } 65 66 // as far was we can tell everything went well 67 return nil 68 }) 69 70 // couldBeDBorYourErr could be one of possible values: 71 // * nil - everything went well, if so, return 72 // * yourError - an error returned from your application, middleware, etc... 73 // * a database error - this is returned if there were problems committing the transaction 74 // * a errNonSuccess - this is returned if the response status code is not between 200..399 75 if couldBeDBorYourErr != nil && !errors.Is(couldBeDBorYourErr, errNonSuccess) { 76 return couldBeDBorYourErr 77 } 78 79 return nil 80 } 81 } 82 } 83 }