package pg

import (
	
	
	

	
)

type (
	BeforeScanHook   = orm.BeforeScanHook
	AfterScanHook    = orm.AfterScanHook
	AfterSelectHook  = orm.AfterSelectHook
	BeforeInsertHook = orm.BeforeInsertHook
	AfterInsertHook  = orm.AfterInsertHook
	BeforeUpdateHook = orm.BeforeUpdateHook
	AfterUpdateHook  = orm.AfterUpdateHook
	BeforeDeleteHook = orm.BeforeDeleteHook
	AfterDeleteHook  = orm.AfterDeleteHook
)

//------------------------------------------------------------------------------

type dummyFormatter struct{}

func (dummyFormatter) ( []byte,  string,  ...interface{}) []byte {
	return append(, ...)
}

// QueryEvent ...
type QueryEvent struct {
	StartTime  time.Time
	DB         orm.DB
	Model      interface{}
	Query      interface{}
	Params     []interface{}
	fmtedQuery []byte
	Result     Result
	Err        error

	Stash map[interface{}]interface{}
}

// QueryHook ...
type QueryHook interface {
	BeforeQuery(context.Context, *QueryEvent) (context.Context, error)
	AfterQuery(context.Context, *QueryEvent) error
}

// UnformattedQuery returns the unformatted query of a query event.
// The query is only valid until the query Result is returned to the user.
func ( *QueryEvent) () ([]byte, error) {
	return queryString(.Query)
}

func ( interface{}) ([]byte, error) {
	switch query := .(type) {
	case orm.TemplateAppender:
		return .AppendTemplate(nil)
	case string:
		return dummyFormatter{}.FormatQuery(nil, ), nil
	default:
		return nil, fmt.Errorf("pg: can't append %T", )
	}
}

// FormattedQuery returns the formatted query of a query event.
// The query is only valid until the query Result is returned to the user.
func ( *QueryEvent) () ([]byte, error) {
	return .fmtedQuery, nil
}

// AddQueryHook adds a hook into query processing.
func ( *baseDB) ( QueryHook) {
	.queryHooks = append(.queryHooks, )
}

func ( *baseDB) (
	 context.Context,
	 orm.DB,
	,  interface{},
	 []interface{},
	 []byte,
) (context.Context, *QueryEvent, error) {
	if len(.queryHooks) == 0 {
		return , nil, nil
	}

	 := &QueryEvent{
		StartTime:  time.Now(),
		DB:         ,
		Model:      ,
		Query:      ,
		Params:     ,
		fmtedQuery: ,
	}

	for ,  := range .queryHooks {
		var  error
		,  = .BeforeQuery(, )
		if  != nil {
			if  := .afterQueryFromIndex(, , );  != nil {
				return , nil, 
			}
			return , nil, 
		}
	}

	return , , nil
}

func ( *baseDB) (
	 context.Context,
	 *QueryEvent,
	 Result,
	 error,
) error {
	if  == nil {
		return nil
	}

	.Err = 
	.Result = 
	return .afterQueryFromIndex(, , len(.queryHooks)-1)
}

func ( *baseDB) ( context.Context,  *QueryEvent,  int) error {
	for ;  >= 0; -- {
		if  := .queryHooks[].AfterQuery(, );  != nil {
			return 
		}
	}
	return nil
}

func ( []QueryHook) []QueryHook {
	return [:len():len()]
}