129 lines
2.6 KiB
Markdown
129 lines
2.6 KiB
Markdown
|
# 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.
|