1
Templates basic CRUD operations using Go Generics.
Go to file
2024-01-28 15:19:39 -06:00
legal basic implementation 2024-01-28 15:19:39 -06:00
context.go basic implementation 2024-01-28 15:19:39 -06:00
creator.go basic implementation 2024-01-28 15:19:39 -06:00
deleter.go basic implementation 2024-01-28 15:19:39 -06:00
doc.go basic implementation 2024-01-28 15:19:39 -06:00
getter.go basic implementation 2024-01-28 15:19:39 -06:00
go.mod basic implementation 2024-01-28 15:19:39 -06:00
go.sum basic implementation 2024-01-28 15:19:39 -06:00
LICENSE basic implementation 2024-01-28 15:19:39 -06:00
lister.go basic implementation 2024-01-28 15:19:39 -06:00
Makefile basic implementation 2024-01-28 15:19:39 -06:00
README.md basic implementation 2024-01-28 15:19:39 -06:00
updater.go basic implementation 2024-01-28 15:19:39 -06:00

gorm-crud

Mostly developed for me. Templates basic CRUD operations using Go Generics.

Usage

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.

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.

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:

func (db *UserDB) GetByEmail(ctx context.Context, email string) (*User, error) {
	return db.Get(ctx, map[string]interface{}{
		"email": email,
	})
}

License

MIT. See LICENSE for more details.