# gorm-crud Mostly developed for me. Templates basic CRUD operations using Go Generics. ## Usage ```shell go get go.pitz.tech/gorm/crud ``` ### Basic The basic usage of this library is as follows. This example demonstrates usage for a single resource type, however this pattern can apply to multiple resources. ```go package main import ( "gorm.io/gorm" "go.pitz.tech/gorm/crud" ) // Resource is an annotated database model. type Resource struct{} // ResourceDB provides an abstraction for managing Resource data in the associated gorm.DB. type ResourceDB struct { List crud.ListFunc[Resource] Create crud.CreateFunc[Resource] Get crud.GetFunc[Resource] Update crud.UpdateFunc[Resource] Delete crud.DeleteFunc } func main() { // todo: open your database var db *gorm.DB resources := &ResourceDB{ List: crud.Lister[Resource](db), Create: crud.Creator[Resource](db), Get: crud.Getter[Resource](db), Update: crud.Updater[Resource](db), Delete: crud.Deleter[Resource](db), } // data, err := resources.List(ctx, 0, 10) } ``` ### Transactions Directly managing transactions is particularly useful when you want to manage multiple resources in a single operation. ```go package main import ( "context" "gorm.io/gorm" "go.pitz.tech/gorm/crud" ) type Resource1 struct {} type Resource2 struct {} type Resource1DB struct { Create crud.CreateFunc[Resource1] } type Resource2DB struct { Create crud.CreateFunc[Resource2] } func main() { // todo: open your database var db *gorm.DB var resource1db *Resource1DB var resource2db *Resource1DB // optionally specify transaction options txn := db.Begin() defer txn.Rollback() ctx := crud.Transaction(context.Background(), txn) err := resource1db.Create(ctx, &Resource1{}) if err != nil { // resource 1 and 2 do not exist! return } err = resource2db.Create(ctx, &Resource2{}) if err != nil { // resource 1 and 2 do not exist! return } err = txn.Commit().Error if err != nil { // resource 1 and 2 do not exist! return } // resource 1 and 2 exist! } ``` ### Extending These methods can easily be customized by providing concrete method definitions in the structure themselves. For example, suppose a `UserDB` wanted to support a `GetByEmail` operation. Such a method might explicitly ask for the email address and call a `Get` function with the explicit field as a filter. For instance: ```go func (db *UserDB) GetByEmail(ctx context.Context, email string) (*User, error) { return db.Get(ctx, map[string]interface{}{ "email": email, }) } ``` ## License `MIT`. See [LICENSE](LICENSE) for more details.