history

package module
v2.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 21, 2020 License: MIT Imports: 12 Imported by: 0

README

gorm history Go Report Card Build Status Coverage Status

You can use the plugin to keep a history of your GORM models changes. Basically it keeps a ledger of your model state. Each model must be associated with a history model which will be a copy of the modified record.

Install

go get github.com/vcraescu/gorm-history

Usage

  1. Register the plugin using db.Use(history.New()):
type Person struct {
    gorm.Model

    FirstName string
    LastName  string
}

type PersonHistory struct {
    gorm.Model
    Entry
}

func main() {
    db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
    if err != nil {
        panic(err)
    }

    db = db.Session(&gorm.Session{})

    err = db.AutoMigrate(Person{}, PersonHistory{})
    if err != nil {
        panic(err)
    }

    plugin := New()
    if err := db.Use(plugin); err != nil {
        return
    }

    db = SetUser(db, history.User{
        ID:    123,
        Email: "john@doe.com",
    })
    db = SetSource(db, history.Source{
        ID:   "1c059a03-3b14-4017-ae33-5337860ec35f",
        Type: "ampq",
    })

    p := Person{
        FirstName: "John",
        LastName:  "Doe",
    }
    if err := db.Save(&p).Error; err != nil {
        panic(err)
    }
}
  1. Your model must implement history.Recordable interface:
func (Person) CreateHistory() interface{} {
	return PersonHistory{}
}
  1. Changes after calling Create, Save and Update will be recorded as long as you pass in the original object.
if err := db.Model(&p).Update("first_name", "Jane").Error; err != nil {
    panic(err)
}

Configuration

Versioning

By default, the plugin generates a new ULID for each history record. You can implement your own versioning function.

type PersonHistory struct {
	gorm.Model
	history.Entry
}

// or 
type PersonHistory struct {
	gorm.Model

	Version  Version `gorm-history:"version"`
	ObjectID uint    `gorm:"index" gorm-history:"objectID"`
	Action   Action  `gorm:"type: string" gorm-history:"action"`
}

You can change the versioning function when you register the plugin:

if err := db.Use(history.New(history.WithVersionFunc(MyVersionFunc))); err != nil {
    panic(err)
}
Copying
  • history.DefaultCopyFunc - copies all the values of the recordable model to history model.

You can change the copy function when you register the plugin if you defined your own copying function:

func myCopyFunc(r Recordable, history interface{}) error {
    // ...
}

//...
if err := db.Use(history.New(history.WithCopyFunc(myCopyFunc))); err != nil {
    panic(err)
}

License

gorm-history is licensed under the MIT License.

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrUnsupportedOperation = errors.New("history is not supported for this operation")
)

Functions

func DefaultCopyFunc

func DefaultCopyFunc(r Recordable, h interface{}) error

func Disable

func Disable(db *gorm.DB) *gorm.DB

func IsDisabled

func IsDisabled(db *gorm.DB) bool

func SetSource

func SetSource(db *gorm.DB, source Source) *gorm.DB

func SetUser

func SetUser(db *gorm.DB, user User) *gorm.DB

Types

type Action

type Action string
const (
	ActionCreate Action = "create"
	ActionUpdate Action = "update"
)

type BlameableHistory

type BlameableHistory interface {
	SetHistoryUserID(id string)
	SetHistoryUserEmail(email string)
}

type Config

type Config struct {
	VersionFunc VersionFunc
	CopyFunc    CopyFunc
}

type ConfigFunc

type ConfigFunc func(c *Config)

func WithCopyFunc

func WithCopyFunc(fn CopyFunc) ConfigFunc

func WithVersionFunc

func WithVersionFunc(fn VersionFunc) ConfigFunc

type Context

type Context struct {
	// contains filtered or unexported fields
}

func (*Context) Action

func (c *Context) Action() Action

func (*Context) DB

func (c *Context) DB() *gorm.DB

func (*Context) History

func (c *Context) History() History

func (*Context) Object

func (c *Context) Object() Recordable

func (*Context) ObjectID

func (c *Context) ObjectID() interface{}

type CopyFunc

type CopyFunc func(r Recordable, h interface{}) error

type Entry

type Entry struct {
	Version    Version   `gorm:"type:char(26)"`
	ObjectID   string    `gorm:"index"`
	Action     Action    `gorm:"type:varchar(24)"`
	UserID     string    `gorm:"type:varchar(255)"`
	UserEmail  string    `gorm:"type:varchar(255)"`
	SourceID   string    `gorm:"type:varchar(255)"`
	SourceType string    `gorm:"type:varchar(255)"`
	CreatedAt  time.Time `gorm:"type:datetime"`
}

func (*Entry) SetHistoryAction

func (e *Entry) SetHistoryAction(action Action)

func (*Entry) SetHistoryCreatedAt

func (e *Entry) SetHistoryCreatedAt(createdAt time.Time)

func (*Entry) SetHistoryObjectID

func (e *Entry) SetHistoryObjectID(id interface{})

func (*Entry) SetHistorySourceID

func (e *Entry) SetHistorySourceID(id string)

func (*Entry) SetHistorySourceType

func (e *Entry) SetHistorySourceType(typ string)

func (*Entry) SetHistoryUserEmail

func (e *Entry) SetHistoryUserEmail(email string)

func (*Entry) SetHistoryUserID

func (e *Entry) SetHistoryUserID(id string)

func (*Entry) SetHistoryVersion

func (e *Entry) SetHistoryVersion(version Version)

type History

type History interface {
	SetHistoryVersion(version Version)
	SetHistoryObjectID(id interface{})
	SetHistoryAction(action Action)
}

type IsZeroer

type IsZeroer interface {
	IsZero() bool
}

type Option

type Option struct{}

type Plugin

type Plugin struct {
	// contains filtered or unexported fields
}
Example
type Person struct {
	gorm.Model

	FirstName string
	LastName  string
}

type PersonHistory struct {
	gorm.Model
	Entry
}

db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
if err != nil {
	panic(err)
}

db = db.Session(&gorm.Session{})

err = db.AutoMigrate(Person{}, PersonHistory{})
if err != nil {
	panic(err)
}

plugin := New()
if err := db.Use(plugin); err != nil {
	return
}

p := Person{
	FirstName: "John",
	LastName:  "Doe",
}
if err := db.Save(&p).Error; err != nil {
	panic(err)
}

func New

func New(configFuncs ...ConfigFunc) *Plugin

func (*Plugin) Initialize

func (p *Plugin) Initialize(db *gorm.DB) error

func (*Plugin) Name

func (p *Plugin) Name() string

type Recordable

type Recordable interface {
	CreateHistory() History
}

type Source

type Source struct {
	ID   string
	Type string
}

func GetSource

func GetSource(db *gorm.DB) (Source, bool)

type SourceableHistory

type SourceableHistory interface {
	SetHistorySourceID(ID string)
	SetHistorySourceType(typ string)
}

type TimestampableHistory

type TimestampableHistory interface {
	SetHistoryCreatedAt(createdAt time.Time)
}

type ULIDVersion

type ULIDVersion struct {
	// contains filtered or unexported fields
}

func NewULIDVersion

func NewULIDVersion() *ULIDVersion

func (*ULIDVersion) Version

func (v *ULIDVersion) Version(ctx *Context) (Version, error)

type User

type User struct {
	ID    string
	Email string
}

func GetUser

func GetUser(db *gorm.DB) (User, bool)

type Version

type Version string

type VersionFunc

type VersionFunc func(ctx *Context) (Version, error)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL