package bun

import (
	
	
	
	
	
	

	
)

type QueryEvent struct {
	DB *DB

	QueryAppender schema.Query
	Query         string
	QueryArgs     []interface{}

	StartTime time.Time
	Result    sql.Result
	Err       error

	Stash map[interface{}]interface{}
}

func ( *QueryEvent) () string {
	if .QueryAppender != nil {
		return .QueryAppender.Operation()
	}
	return queryOperation(.Query)
}

func ( string) string {
	if  := strings.IndexByte(, ' ');  > 0 {
		 = [:]
	}
	if len() > 16 {
		 = [:16]
	}
	return 
}

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

func ( *DB) (
	 context.Context,
	 schema.Query,
	 string,
	 []interface{},
) (context.Context, *QueryEvent) {
	atomic.AddUint64(&.stats.Queries, 1)

	if len(.queryHooks) == 0 {
		return , nil
	}

	 := &QueryEvent{
		DB: ,

		QueryAppender: ,
		Query:         ,
		QueryArgs:     ,

		StartTime: time.Now(),
	}

	for ,  := range .queryHooks {
		 = .BeforeQuery(, )
	}

	return , 
}

func ( *DB) (
	 context.Context,
	 *QueryEvent,
	 sql.Result,
	 error,
) {
	switch  {
	case nil, sql.ErrNoRows:
		// nothing
	default:
		atomic.AddUint64(&.stats.Errors, 1)
	}

	if  == nil {
		return
	}

	.Result = 
	.Err = 

	.afterQueryFromIndex(, , len(.queryHooks)-1)
}

func ( *DB) ( context.Context,  *QueryEvent,  int) {
	for ;  >= 0; -- {
		.queryHooks[].AfterQuery(, )
	}
}

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

func ( context.Context,  reflect.Value) error {
	return .Interface().(schema.BeforeScanHook).BeforeScan()
}

func ( context.Context,  reflect.Value) error {
	return .Interface().(schema.AfterScanHook).AfterScan()
}