func (b *Builder) ExecContextOK(ctx context.Context, execContexter ExecContexter) error {
	if execContexter == nil {
		return nil
	}
	ev := reflect.ValueOf(execContexter)
	if ev.Kind() == reflect.Ptr && ev.Pointer() == 0 {
		return nil
	}
	_, err := execContexter.ExecContext(ctx)
	return err
}
ExecContextOK is an alias for ExecContext and discard result, just return the error.
If execer is nil then it's a no-op and nil error is returned.
package tmetadbr
import (
	"bytes"
	"context"
	"database/sql"
	"errors"
	"fmt"
	"reflect"
	"strings"
	"github.com/gocaveman/tmeta"
	"github.com/gocraft/dbr"
	"github.com/gocraft/dbr/dialect"
)
var (
	ErrTypeNotRegistered = errors.New("tmetadbr: type not registered")
	ErrUpdateFailed = &errorWithCode{code: 409, msg: "tmetadbr: update failed (not found or version conflict)"}
)
type Session interface {
	InsertInto(table string) *dbr.InsertStmt
	Select(column ...string) *dbr.SelectStmt
	Update(table string) *dbr.UpdateStmt
	DeleteFrom(table string) *dbr.DeleteStmt
	InsertBySql(query string, value ...interface{}) *dbr.InsertStmt
	SelectBySql(query string, value ...interface{}) *dbr.SelectStmt
	UpdateBySql(query string, value ...interface{}) *dbr.UpdateStmt
	DeleteBySql(query string, value ...interface{}) *dbr.DeleteStmt
}
var (
	_ Session = &dbr.Session{}
	_ Session = &dbr.Tx{}
)
func New(sess Session, meta *tmeta.Meta) *Builder {
	return &Builder{
		Session: sess,
		Meta:    meta,
	}
}
type Builder struct {
	Session Session
	*tmeta.Meta
}
func (b *Builder) dbrDialect() dbr.Dialect {
	f := derefValue(reflect.ValueOf(b.Session)).FieldByName("Dialect")
	if !f.IsValid() {
		panic("unable to find Dialect field on Session")
	}
	return f.Interface().(dbr.Dialect)
}
func (b *Builder) MustSelect(o interface{}) *dbr.SelectStmt {
	ret, err := b.Select(o)
	if err != nil {
		panic(err)
	}
	return ret
}
func (b *Builder) Select(o interface{}) (*dbr.SelectStmt, error) {
	ti := b.Meta.ForType(elemDerefType(reflect.TypeOf(o)))
	if ti == nil {
		return nil, ErrTypeNotRegistered
	}
	return b.Session.
			Select(ti.SQLFields(true)...).
			From(ti.SQLName()),
		nil
}
func (b *Builder) MustSelectByID(o interface{}, ids ...interface{}) *dbr.SelectStmt {
	ret, err := b.SelectByID(o, ids...)
	if err != nil {
		panic(err)
	}
	return ret
}
func (b *Builder) SelectByID(o interface{}, ids ...interface{}) (*dbr.SelectStmt, error) {
	ti := b.Meta.ForType(elemDerefType(reflect.TypeOf(o)))
	if ti == nil {
		return nil, ErrTypeNotRegistered
	}
	if len(ids) == 0 {
		ids = ti.PKValues(o)
	}
	return b.Session.
			Select(ti.SQLFields(true)...).
			From(ti.SQLName()).
			Where(ti.SQLPKWhere(), ids...),
		nil
}
func (b *Builder) MustInsert(o interface{}) *dbr.InsertStmt {
	ret, err := b.Insert(o)
	if err != nil {
		panic(err)
	}
	return ret
}
func (b *Builder) Insert(o interface{}) (*dbr.InsertStmt, error) {
	ti := b.Meta.ForType(elemDerefType(reflect.TypeOf(o)))
	if ti == nil {
		return nil, ErrTypeNotRegistered
	}
	stmt := b.Session.
		InsertInto(ti.SQLName()).
		Columns(ti.SQLFields(!ti.PKAutoIncr())...)
	ov := derefValue(reflect.ValueOf(o))
	if ov.Kind() == reflect.Slice {  
		for i := 0; i < ov.Len(); i++ {
			elv := ov.Index(i)
			var el interface{}
			if elv.Kind() != reflect.Ptr {  
				el = elv.Addr().Interface()
			} else {
				el = elv.Interface()
			}
			if ida, ok := el.(IDAssigner); ok {
				ida.IDAssign()
			}
			if ctt, ok := el.(CreateTimeToucher); ok {
				ctt.CreateTimeTouch()
			}
			if ctt, ok := el.(UpdateTimeToucher); ok {
				ctt.UpdateTimeTouch()
			}
			stmt = stmt.Record(el)
		}
	} else {  
		if ida, ok := o.(IDAssigner); ok {
			ida.IDAssign()
		}
		if ctt, ok := o.(CreateTimeToucher); ok {
			ctt.CreateTimeTouch()
		}
		if ctt, ok := o.(UpdateTimeToucher); ok {
			ctt.UpdateTimeTouch()
		}
		stmt = stmt.Record(o)
	}
	return stmt, nil
}
func (b *Builder) MustUpdateByID(o interface{}) *dbr.UpdateStmt {
	ret, err := b.UpdateByID(o)
	if err != nil {
		panic(err)
	}
	return ret
}
func (b *Builder) UpdateByID(o interface{}) (*dbr.UpdateStmt, error) {
	ti := b.Meta.For(o)
	if ti == nil {
		return nil, ErrTypeNotRegistered
	}
	po := o
	if reflect.TypeOf(po).Kind() != reflect.Ptr {  
		po = reflect.ValueOf(po).Addr().Interface()
	}
	if ctt, ok := po.(UpdateTimeToucher); ok {
		ctt.UpdateTimeTouch()
	}
	vmap := ti.SQLValueMap(o, false)
	var curVer interface{}
	if ti.SQLVersionField() != "" {
		curVer = vmap[ti.SQLVersionField()]
		if vi, ok := o.(VersionIncrementer); ok {
			vi.VersionIncrement()
			vmap2 := ti.SQLValueMap(o, false)  
			vmap[ti.SQLVersionField()] = vmap2[ti.SQLVersionField()]
		} else {
			return nil, fmt.Errorf("SQLVersionField is set to %q but VersionIncrement not implemented for type %T", ti.SQLVersionField(), o)
		}
	}
	ustmt := b.Session.
		Update(ti.SQLName()).
		SetMap(vmap).
		Where(ti.SQLPKWhere(), ti.PKValues(o)...)
	if ti.SQLVersionField() != "" {  
		ustmt = ustmt.Where(ti.SQLVersionField()+" = ?", curVer)
	}
	return ustmt, nil
}
func (b *Builder) MustDeleteByID(o interface{}, ids ...interface{}) *dbr.DeleteStmt {
	ret, err := b.DeleteByID(o, ids...)
	if err != nil {
		panic(err)
	}
	return ret
}
func (b *Builder) DeleteByID(o interface{}, ids ...interface{}) (*dbr.DeleteStmt, error) {
	ti := b.Meta.For(o)
	if ti == nil {
		return nil, ErrTypeNotRegistered
	}
	dstmt := b.Session.DeleteFrom(ti.SQLName())
	if len(ids) == 0 {
		ids = ti.PKValues(o)
		if ti.SQLVersionField() != "" {
			dstmt = dstmt.Where(ti.SQLVersionField()+" = ?",
				sqlFieldValue(reflect.ValueOf(o), ti.SQLVersionField()))
		}
	}
	dstmt = dstmt.Where(ti.SQLPKWhere(), ids...)
	return dstmt, nil
}
func (b *Builder) MustSelectRelation(o interface{}, relationName string) (stmt *dbr.SelectStmt) {
	var err error
	stmt, err = b.SelectRelation(o, relationName)
	if err != nil {
		panic(err)
	}
	return
}
func (b *Builder) SelectRelation(o interface{}, relationName string) (stmt *dbr.SelectStmt, reterr error) {
	stmt, _, reterr = b.SelectRelationPtr(o, relationName)
	return
}
func (b *Builder) MustSelectRelationPtr(o interface{}, relationName string) (stmt *dbr.SelectStmt, fieldPtr interface{}) {
	var err error
	stmt, fieldPtr, err = b.SelectRelationPtr(o, relationName)
	if err != nil {
		panic(err)
	}
	return
}
func (b *Builder) SelectRelationPtr(o interface{}, relationName string) (stmt *dbr.SelectStmt, fieldPtr interface{}, reterr error) {
	ti := b.Meta.For(o)
	if ti == nil {
		return nil, nil, ErrTypeNotRegistered
	}
	rel := ti.RelationNamed(relationName)
	if rel == nil {
		return nil, nil, fmt.Errorf("relation %q not found", relationName)
	}
	vo := derefValue(reflect.ValueOf(o))
	switch r := rel.(type) {
	case *tmeta.BelongsTo:
		gvf := vo.FieldByName(r.GoValueField)
		targetType := derefType(gvf.Type())
		targetTI := b.Meta.ForType(targetType)
		if targetTI == nil {
			return nil, nil, fmt.Errorf("%T is not registered", gvf.Interface())
		}
		stmt = b.Session.
			Select(targetTI.SQLFields(true)...).
			From(targetTI.SQLName()).
			Where(targetTI.SQLPKFields()[0]+" = ?",
				sqlFieldValue(vo, r.SQLIDField))
		fieldPtr = ti.RelationTargetPtr(o, relationName)
		return
	case *tmeta.HasMany:
		gvf := vo.FieldByName(r.GoValueField)
		targetType := elemDerefType(gvf.Type())  
		targetTI := b.Meta.ForType(targetType)
		if targetTI == nil {
			return nil, nil, fmt.Errorf("%T is not registered", gvf.Interface())
		}
		stmt = b.Session.
			Select(targetTI.SQLFields(true)...).
			From(targetTI.SQLName()).
			Where(r.SQLOtherIDField+" = ?", ti.PKValues(o)[0])
		fieldPtr = ti.RelationTargetPtr(o, relationName)
		return
	case *tmeta.HasOne:
		gvf := vo.FieldByName(r.GoValueField)
		targetType := derefType(gvf.Type())
		targetTI := b.Meta.ForType(targetType)
		if targetTI == nil {
			return nil, nil, fmt.Errorf("%T is not registered", gvf.Interface())
		}
		stmt = b.Session.
			Select(targetTI.SQLFields(true)...).
			From(targetTI.SQLName()).
			Where(r.SQLOtherIDField+" = ?", ti.PKValues(o)[0])
		fieldPtr = ti.RelationTargetPtr(o, relationName)
		return
	case *tmeta.BelongsToMany:
		joinTI := b.Meta.ForName(r.JoinName)
		targetType := elemDerefType(vo.FieldByName(r.GoValueField).Type())
		targetTI := b.Meta.ForType(targetType)
		stmt = b.Session.
			Select(
				stringsAddPrefix(targetTI.SQLFields(true), targetTI.SQLName()+".")...,
			).
			From(joinTI.SQLName()).
			Join(targetTI.SQLName(),
				fmt.Sprintf(`%s.%s = %s.%s`,
					joinTI.SQLName(), r.SQLOtherIDField,
					targetTI.SQLName(), targetTI.SQLPKFields()[0],
				)).
			Where(joinTI.SQLName()+"."+r.SQLIDField+" = ?", ti.PKValues(o)[0])
		fieldPtr = ti.RelationTargetPtr(o, relationName)
		return
	case *tmeta.BelongsToManyIDs:
		joinTI := b.Meta.ForName(r.JoinName)
		stmt = b.Session.
			Select(r.SQLOtherIDField).
			From(joinTI.SQLName()).
			Where(r.SQLIDField+" = ?", ti.PKValues(o)[0])
		fieldPtr = ti.RelationTargetPtr(o, relationName)
		return
	}
	return nil, nil, fmt.Errorf("relation %q is not of a suppported type", relationName)
}
func (b *Builder) MustDeleteRelationNotIn(o interface{}, relationName string) *dbr.DeleteStmt {
	ret, err := b.DeleteRelationNotIn(o, relationName)
	if err != nil {
		panic(err)
	}
	return ret
}
func (b *Builder) DeleteRelationNotIn(o interface{}, relationName string) (*dbr.DeleteStmt, error) {
	ti := b.Meta.For(o)
	if ti == nil {
		return nil, ErrTypeNotRegistered
	}
	rel := ti.RelationNamed(relationName)
	if rel == nil {
		return nil, fmt.Errorf("relation %q not found", relationName)
	}
	switch relv := rel.(type) {
	case *tmeta.BelongsToManyIDs:
		vo := derefValue(reflect.ValueOf(o))
		sliceV := derefValue(vo.FieldByName(relv.GoValueField))
		joinTI := b.Meta.ForName(relv.JoinName)
		stmt := b.Session.DeleteFrom(joinTI.SQLName())
		stmt = stmt.Where(relv.SQLIDField+" = ?", ti.PKValues(o)[0])
		if sliceV.Len() > 0 {
			stmt = stmt.Where(relv.SQLOtherIDField+" NOT IN ?", sliceV.Interface())
		}
		return stmt, nil
	}
	return nil, fmt.Errorf("unsupported relation type %T for DeleteRelationNotIn", rel)
}
func (b *Builder) MustInsertRelationIgnore(o interface{}, relationName string) *dbr.InsertStmt {
	ret, err := b.InsertRelationIgnore(o, relationName)
	if err != nil {
		panic(err)
	}
	return ret
}
func (b *Builder) InsertRelationIgnore(o interface{}, relationName string) (*dbr.InsertStmt, error) {
	ti := b.Meta.For(o)
	if ti == nil {
		return nil, ErrTypeNotRegistered
	}
	rel := ti.RelationNamed(relationName)
	if rel == nil {
		return nil, fmt.Errorf("relation %q not found", relationName)
	}
	switch relv := rel.(type) {
	case *tmeta.BelongsToManyIDs:
		joinTI := b.Meta.ForName(relv.JoinName)
		thisID := ti.PKValues(o)[0]  
		vo := derefValue(reflect.ValueOf(o))
		sliceV := derefValue(vo.FieldByName(relv.GoValueField))
		if sliceV.Len() == 0 {
			return nil, nil
		}
		var buf bytes.Buffer
		var args []interface{}
		for i := 0; i < sliceV.Len(); i++ {
			buf.WriteString(`(?,?),`)
			elV := derefValue(sliceV.Index(i))
			args = append(args, thisID)
			args = append(args, elV.Interface())
		}
		var valueStr = strings.TrimSuffix(buf.String(), ",")
		switch b.dbrDialect() {
		case dialect.SQLite3:
			return b.Session.InsertBySql(
					`INSERT OR IGNORE INTO `+joinTI.SQLName()+
						`(`+relv.SQLIDField+`,`+relv.SQLOtherIDField+`)`+
						` VALUES `+valueStr, args...),
				nil
		case dialect.MySQL:
			return b.Session.InsertBySql(
					`INSERT IGNORE INTO `+joinTI.SQLName()+
						`(`+relv.SQLIDField+`,`+relv.SQLOtherIDField+`)`+
						` VALUES `+valueStr, args...),
				nil
		case dialect.PostgreSQL:
			return b.Session.InsertBySql(
					`INSERT INTO `+joinTI.SQLName()+
						`(`+relv.SQLIDField+`,`+relv.SQLOtherIDField+`)`+
						` VALUES `+valueStr+` ON CONFLICT DO NOTHING`, args...),
				nil
		}
		return nil, fmt.Errorf("unknown dialect %#v", b.dbrDialect())
	}
	return nil, fmt.Errorf("unsupported relation type %T for DeleteRelationNotIn", rel)
}
type Execer interface {
	Exec() (sql.Result, error)
}
type ExecContexter interface {
	ExecContext(ctx context.Context) (sql.Result, error)
}
func (b *Builder) ExecOK(execer Execer) error {
	if execer == nil {
		return nil
	}
	ev := reflect.ValueOf(execer)
	if ev.Kind() == reflect.Ptr && ev.Pointer() == 0 {
		return nil
	}
	_, err := execer.Exec()
	return err
}