package orm import ( "context" "database/sql" "errors" "fmt" "reflect" "github.com/go-pg/pg/types" ) var errModelNil = errors.New("pg: Model(nil)") type useQueryOne interface { useQueryOne() bool } type HooklessModel interface { // Init is responsible to initialize/reset model state. // It is called only once no matter how many rows // were returned by database. Init() error // NewModel returns ColumnScanner that is used to scan columns // from the current row. It is called once for every row. NewModel() ColumnScanner // AddModel adds ColumnScanner created by NewModel to the Collection. AddModel(ColumnScanner) error } type Model interface { HooklessModel AfterQuery(context.Context, DB) error BeforeSelectQuery(context.Context, DB, *Query) (*Query, error) AfterSelect(context.Context, DB) error BeforeInsert(context.Context, DB) error AfterInsert(context.Context, DB) error BeforeUpdate(context.Context, DB) error AfterUpdate(context.Context, DB) error BeforeDelete(context.Context, DB) error AfterDelete(context.Context, DB) error } func NewModel(values ...interface{}) (Model, error) { if len(values) > 1 { return Scan(values...), nil } v0 := values[0] switch v0 := v0.(type) { case Model: return v0, nil case HooklessModel: return newModelWithHookStubs(v0), nil case types.ValueScanner, sql.Scanner: return Scan(v0), nil } v := reflect.ValueOf(v0) if !v.IsValid() { return nil, errModelNil } if v.Kind() != reflect.Ptr { return nil, fmt.Errorf("pg: Model(non-pointer %T)", v0) } v = v.Elem() switch v.Kind() { case reflect.Struct: if v.Type() != timeType { return newStructTableModelValue(v), nil } case reflect.Slice: typ := v.Type() elemType := indirectType(typ.Elem()) if elemType.Kind() == reflect.Struct && elemType != timeType { return newSliceTableModel(v, elemType), nil } else { return newSliceModel(v, elemType), nil } } return Scan(v0), nil } type modelWithHookStubs struct { hookStubs HooklessModel } func newModelWithHookStubs(m HooklessModel) Model { return modelWithHookStubs{ HooklessModel: m, } }