package bun

import (
	
	
	
	
	

	
	
	
)

const (
	wherePKFlag internal.Flag = 1 << iota
	forceDeleteFlag
	deletedFlag
	allWithDeletedFlag
)

type withQuery struct {
	name  string
	query schema.QueryAppender
}

// IConn is a common interface for *sql.DB, *sql.Conn, and *sql.Tx.
type IConn interface {
	QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
	ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
	QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row
}

var (
	_ IConn = (*sql.DB)(nil)
	_ IConn = (*sql.Conn)(nil)
	_ IConn = (*sql.Tx)(nil)
	_ IConn = (*DB)(nil)
	_ IConn = (*Conn)(nil)
	_ IConn = (*Tx)(nil)
)

// IDB is a common interface for *bun.DB, bun.Conn, and bun.Tx.
type IDB interface {
	IConn

	NewValues(model interface{}) *ValuesQuery
	NewSelect() *SelectQuery
	NewInsert() *InsertQuery
	NewUpdate() *UpdateQuery
	NewDelete() *DeleteQuery
	NewCreateTable() *CreateTableQuery
	NewDropTable() *DropTableQuery
	NewCreateIndex() *CreateIndexQuery
	NewDropIndex() *DropIndexQuery
	NewTruncateTable() *TruncateTableQuery
	NewAddColumn() *AddColumnQuery
	NewDropColumn() *DropColumnQuery
}

var (
	_ IConn = (*DB)(nil)
	_ IConn = (*Conn)(nil)
	_ IConn = (*Tx)(nil)
)

type baseQuery struct {
	db   *DB
	conn IConn

	model model
	err   error

	tableModel tableModel
	table      *schema.Table

	with       []withQuery
	modelTable schema.QueryWithArgs
	tables     []schema.QueryWithArgs
	columns    []schema.QueryWithArgs

	flags internal.Flag
}

func ( *baseQuery) () *DB {
	return .db
}

func ( *baseQuery) () Model {
	return .model
}

func ( *baseQuery) ( IConn) {
	// Unwrap Bun wrappers to not call query hooks twice.
	switch db := .(type) {
	case *DB:
		.conn = .DB
	case Conn:
		.conn = .Conn
	case Tx:
		.conn = .Tx
	default:
		.conn = 
	}
}

// TODO: rename to setModel
func ( *baseQuery) ( interface{}) {
	,  := newSingleModel(.db, )
	if  != nil {
		.setErr()
		return
	}

	.model = 
	if ,  := .(tableModel);  {
		.tableModel = 
		.table = .Table()
	}
}

func ( *baseQuery) ( error) {
	if .err == nil {
		.err = 
	}
}

func ( *baseQuery) ( []interface{}) (model, error) {
	if len() == 0 {
		if .model != nil {
			return .model, nil
		}
		return nil, errNilModel
	}
	return newModel(.db, )
}

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

func ( *baseQuery) () error {
	if .table == nil {
		return errors.New("bun: can't use soft deletes without a table")
	}
	if .table.SoftDeleteField == nil {
		return fmt.Errorf("%s does not have a soft delete field", .table)
	}
	if .tableModel == nil {
		return errors.New("bun: can't use soft deletes without a table model")
	}
	return nil
}

// Deleted adds `WHERE deleted_at IS NOT NULL` clause for soft deleted models.
func ( *baseQuery) () {
	if  := .checkSoftDelete();  != nil {
		.setErr()
		return
	}
	.flags = .flags.Set(deletedFlag)
	.flags = .flags.Remove(allWithDeletedFlag)
}

// AllWithDeleted changes query to return all rows including soft deleted ones.
func ( *baseQuery) () {
	if  := .checkSoftDelete();  != nil {
		.setErr()
		return
	}
	.flags = .flags.Set(allWithDeletedFlag)
	.flags = .flags.Remove(deletedFlag)
}

func ( *baseQuery) () bool {
	if .table != nil {
		return .table.SoftDeleteField != nil && !.flags.Has(allWithDeletedFlag)
	}
	return false
}

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

func ( *baseQuery) ( string,  schema.QueryAppender) {
	.with = append(.with, withQuery{
		name:  ,
		query: ,
	})
}

func ( *baseQuery) ( schema.Formatter,  []byte) ( []byte,  error) {
	if len(.with) == 0 {
		return , nil
	}

	 = append(, "WITH "...)
	for ,  := range .with {
		if  > 0 {
			 = append(, ", "...)
		}

		 = .AppendIdent(, .name)
		if ,  := .query.(schema.ColumnsAppender);  {
			 = append(, " ("...)
			,  = .AppendColumns(, )
			if  != nil {
				return nil, 
			}
			 = append(, ")"...)
		}

		 = append(, " AS ("...)

		,  = .query.AppendQuery(, )
		if  != nil {
			return nil, 
		}

		 = append(, ')')
	}
	 = append(, ' ')
	return , nil
}

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

func ( *baseQuery) ( schema.QueryWithArgs) {
	.tables = append(.tables, )
}

func ( *baseQuery) ( schema.QueryWithArgs) {
	.columns = append(.columns, )
}

func ( *baseQuery) ( []string) {
	if .columns == nil {
		for ,  := range .table.Fields {
			.columns = append(.columns, schema.UnsafeIdent(.Name))
		}
	}

	if len() == 1 && [0] == "*" {
		.columns = make([]schema.QueryWithArgs, 0)
		return
	}

	for ,  := range  {
		if !._excludeColumn() {
			.setErr(fmt.Errorf("bun: can't find column=%q", ))
			return
		}
	}
}

func ( *baseQuery) ( string) bool {
	for ,  := range .columns {
		if .Args == nil && .Query ==  {
			.columns = append(.columns[:], .columns[+1:]...)
			return true
		}
	}
	return false
}

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

func ( *baseQuery) () bool {
	if !.modelTable.IsZero() {
		return .modelTable.Query != ""
	}
	return .table != nil
}

func ( *baseQuery) () bool {
	return .modelHasTableName() || len(.tables) > 0
}

func ( *baseQuery) (
	 schema.Formatter,  []byte,
) ( []byte,  error) {
	return ._appendTables(, , false)
}

func ( *baseQuery) (
	 schema.Formatter,  []byte,
) ( []byte,  error) {
	return ._appendTables(, , true)
}

func ( *baseQuery) (
	 schema.Formatter,  []byte,  bool,
) ( []byte,  error) {
	 := len()

	if .modelHasTableName() {
		if !.modelTable.IsZero() {
			,  = .modelTable.AppendQuery(, )
			if  != nil {
				return nil, 
			}
		} else {
			 = .AppendQuery(, string(.table.SQLNameForSelects))
			if  && .table.SQLAlias != .table.SQLNameForSelects {
				 = append(, " AS "...)
				 = append(, .table.SQLAlias...)
			}
		}
	}

	for ,  := range .tables {
		if len() >  {
			 = append(, ", "...)
		}
		,  = .AppendQuery(, )
		if  != nil {
			return nil, 
		}
	}

	return , nil
}

func ( *baseQuery) ( schema.Formatter,  []byte) ([]byte, error) {
	return ._appendFirstTable(, , false)
}

func ( *baseQuery) (
	 schema.Formatter,  []byte,
) ([]byte, error) {
	return ._appendFirstTable(, , true)
}

func ( *baseQuery) (
	 schema.Formatter,  []byte,  bool,
) ([]byte, error) {
	if !.modelTable.IsZero() {
		return .modelTable.AppendQuery(, )
	}

	if .table != nil {
		 = .AppendQuery(, string(.table.SQLName))
		if  {
			 = append(, " AS "...)
			 = append(, .table.SQLAlias...)
		}
		return , nil
	}

	if len(.tables) > 0 {
		return .tables[0].AppendQuery(, )
	}

	return nil, errors.New("bun: query does not have a table")
}

func ( *baseQuery) () bool {
	if .modelHasTableName() {
		return len(.tables) >= 1
	}
	return len(.tables) >= 2
}

func ( *baseQuery) ( schema.Formatter,  []byte) ( []byte,  error) {
	 := .tables
	if !.modelHasTableName() {
		 = [1:]
	}
	for ,  := range  {
		if  > 0 {
			 = append(, ", "...)
		}
		,  = .AppendQuery(, )
		if  != nil {
			return nil, 
		}
	}
	return , nil
}

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

func ( *baseQuery) ( schema.Formatter,  []byte) ( []byte,  error) {
	for ,  := range .columns {
		if  > 0 {
			 = append(, ", "...)
		}
		,  = .AppendQuery(, )
		if  != nil {
			return nil, 
		}
	}
	return , nil
}

func ( *baseQuery) () ([]*schema.Field, error) {
	if len(.columns) == 0 {
		return .table.Fields, nil
	}
	return ._getFields(false)
}

func ( *baseQuery) () ([]*schema.Field, error) {
	if len(.columns) == 0 {
		return .table.DataFields, nil
	}
	return ._getFields(true)
}

func ( *baseQuery) ( bool) ([]*schema.Field, error) {
	 := make([]*schema.Field, 0, len(.columns))
	for ,  := range .columns {
		if .Args != nil {
			continue
		}

		,  := .table.Field(.Query)
		if  != nil {
			return nil, 
		}

		if  && .IsPK {
			continue
		}

		 = append(, )
	}
	return , nil
}

func ( *baseQuery) (
	 context.Context,
	 schema.Query,
	 string,
	 model,
	 bool,
) (sql.Result, error) {
	,  := .db.beforeQuery(, , , nil)

	,  := .conn.QueryContext(, )
	if  != nil {
		.db.afterQuery(, , nil, )
		return nil, 
	}
	defer .Close()

	,  := .ScanRows(, )
	if  != nil {
		.db.afterQuery(, , nil, )
		return nil, 
	}

	if  == 0 &&  && isSingleRowModel() {
		 = sql.ErrNoRows
	}

	 := driver.RowsAffected()
	.db.afterQuery(, , , )

	return , 
}

func ( *baseQuery) (
	 context.Context,
	 schema.Query,
	 string,
) (sql.Result, error) {
	,  := .db.beforeQuery(, , , nil)

	,  := .conn.ExecContext(, )
	if  != nil {
		.db.afterQuery(, , nil, )
		return , 
	}

	.db.afterQuery(, , , )
	return , nil
}

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

func ( *baseQuery) ( schema.Formatter,  []byte,  string) ([]byte, bool) {
	if .table == nil {
		return , false
	}

	if ,  := .tableModel.(*structTableModel);  {
		if ,  := .AppendNamedArg(, , );  {
			return , 
		}
	}

	switch  {
	case "TableName":
		 = .AppendQuery(, string(.table.SQLName))
		return , true
	case "TableAlias":
		 = .AppendQuery(, string(.table.SQLAlias))
		return , true
	case "PKs":
		 = appendColumns(, "", .table.PKs)
		return , true
	case "TablePKs":
		 = appendColumns(, .table.SQLAlias, .table.PKs)
		return , true
	case "Columns":
		 = appendColumns(, "", .table.Fields)
		return , true
	case "TableColumns":
		 = appendColumns(, .table.SQLAlias, .table.Fields)
		return , true
	}

	return , false
}

func ( []byte,  schema.Safe,  []*schema.Field) []byte {
	for ,  := range  {
		if  > 0 {
			 = append(, ", "...)
		}

		if len() > 0 {
			 = append(, ...)
			 = append(, '.')
		}
		 = append(, .SQLName...)
	}
	return 
}

func ( schema.Formatter,  schema.NamedArgAppender) schema.Formatter {
	if .IsNop() {
		return 
	}
	return .WithArg()
}

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

type whereBaseQuery struct {
	baseQuery

	where []schema.QueryWithSep
}

func ( *whereBaseQuery) ( schema.QueryWithSep) {
	.where = append(.where, )
}

func ( *whereBaseQuery) ( string,  []schema.QueryWithSep) {
	if len() == 0 {
		return
	}

	.addWhere(schema.SafeQueryWithSep("", nil, ))
	.addWhere(schema.SafeQueryWithSep("", nil, "("))

	[0].Sep = ""
	.where = append(.where, ...)

	.addWhere(schema.SafeQueryWithSep("", nil, ")"))
}

func ( *whereBaseQuery) (
	 schema.Formatter,  []byte,  bool,
) ([]byte, error) {
	if len(.where) == 0 && !.flags.Has(wherePKFlag) {
		 := errors.New("bun: Update and Delete queries require at least one Where")
		return nil, 
	}
	return .appendWhere(, , )
}

func ( *whereBaseQuery) (
	 schema.Formatter,  []byte,  bool,
) ( []byte,  error) {
	if len(.where) == 0 && !.isSoftDelete() && !.flags.Has(wherePKFlag) {
		return , nil
	}

	 = append(, " WHERE "...)
	 := len()

	if len(.where) > 0 {
		,  = appendWhere(, , .where)
		if  != nil {
			return nil, 
		}
	}

	if .isSoftDelete() {
		if len() >  {
			 = append(, " AND "...)
		}
		if  {
			 = append(, .tableModel.Table().SQLAlias...)
			 = append(, '.')
		}
		 = append(, .tableModel.Table().SoftDeleteField.SQLName...)
		if .flags.Has(deletedFlag) {
			 = append(, " IS NOT NULL"...)
		} else {
			 = append(, " IS NULL"...)
		}
	}

	if .flags.Has(wherePKFlag) {
		if len() >  {
			 = append(, " AND "...)
		}
		,  = .appendWherePK(, , )
		if  != nil {
			return nil, 
		}
	}

	return , nil
}

func (
	 schema.Formatter,  []byte,  []schema.QueryWithSep,
) ( []byte,  error) {
	for ,  := range  {
		if  > 0 {
			 = append(, .Sep...)
		}

		if .Query == "" {
			continue
		}

		 = append(, '(')
		,  = .AppendQuery(, )
		if  != nil {
			return nil, 
		}
		 = append(, ')')
	}
	return , nil
}

func ( *whereBaseQuery) (
	 schema.Formatter,  []byte,  bool,
) ( []byte,  error) {
	if .table == nil {
		 := fmt.Errorf("bun: got %T, but WherePK requires a struct or slice-based model", .model)
		return nil, 
	}
	if  := .table.CheckPKs();  != nil {
		return nil, 
	}

	switch model := .tableModel.(type) {
	case *structTableModel:
		return .appendWherePKStruct(, , , )
	case *sliceTableModel:
		return .appendWherePKSlice(, , , )
	}

	return nil, fmt.Errorf("bun: WherePK does not support %T", .tableModel)
}

func ( *whereBaseQuery) (
	 schema.Formatter,  []byte,  *structTableModel,  bool,
) ( []byte,  error) {
	if !.strct.IsValid() {
		return nil, errNilModel
	}

	 := .IsNop()
	 = append(, '(')
	for ,  := range .table.PKs {
		if  > 0 {
			 = append(, " AND "...)
		}
		if  {
			 = append(, .table.SQLAlias...)
			 = append(, '.')
		}
		 = append(, .SQLName...)
		 = append(, " = "...)
		if  {
			 = append(, '?')
		} else {
			 = .AppendValue(, , .strct)
		}
	}
	 = append(, ')')
	return , nil
}

func ( *whereBaseQuery) (
	 schema.Formatter,  []byte,  *sliceTableModel,  bool,
) ( []byte,  error) {
	if len(.table.PKs) > 1 {
		 = append(, '(')
	}
	if  {
		 = appendColumns(, .table.SQLAlias, .table.PKs)
	} else {
		 = appendColumns(, "", .table.PKs)
	}
	if len(.table.PKs) > 1 {
		 = append(, ')')
	}

	 = append(, " IN ("...)

	 := .IsNop()
	 := .slice
	 := .Len()
	for  := 0;  < ; ++ {
		if  > 0 {
			if  {
				break
			}
			 = append(, ", "...)
		}

		 := indirect(.Index())

		if len(.table.PKs) > 1 {
			 = append(, '(')
		}
		for ,  := range .table.PKs {
			if  > 0 {
				 = append(, ", "...)
			}
			if  {
				 = append(, '?')
			} else {
				 = .AppendValue(, , )
			}
		}
		if len(.table.PKs) > 1 {
			 = append(, ')')
		}
	}

	 = append(, ')')

	return , nil
}

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

type returningQuery struct {
	returning       []schema.QueryWithArgs
	returningFields []*schema.Field
}

func ( *returningQuery) ( schema.QueryWithArgs) {
	.returning = append(.returning, )
}

func ( *returningQuery) ( *schema.Field) {
	if len(.returning) > 0 {
		return
	}
	for ,  := range .returningFields {
		if  ==  {
			return
		}
	}
	.returningFields = append(.returningFields, )
}

func ( *returningQuery) () bool {
	if len(.returning) == 1 {
		switch .returning[0].Query {
		case "null", "NULL":
			return false
		}
	}
	return len(.returning) > 0 || len(.returningFields) > 0
}

func ( *returningQuery) (
	 schema.Formatter,  []byte,
) ( []byte,  error) {
	if !.hasReturning() {
		return , nil
	}

	 = append(, " RETURNING "...)

	for ,  := range .returning {
		if  > 0 {
			 = append(, ", "...)
		}
		,  = .AppendQuery(, )
		if  != nil {
			return nil, 
		}
	}

	if len(.returning) > 0 {
		return , nil
	}

	 = appendColumns(, "", .returningFields)
	return , nil
}

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

type columnValue struct {
	column string
	value  schema.QueryWithArgs
}

type customValueQuery struct {
	modelValues map[string]schema.QueryWithArgs
	extraValues []columnValue
}

func ( *customValueQuery) (
	 *schema.Table,  string,  string,  []interface{},
) {
	if ,  := .FieldMap[];  {
		if .modelValues == nil {
			.modelValues = make(map[string]schema.QueryWithArgs)
		}
		.modelValues[] = schema.SafeQuery(, )
	} else {
		.extraValues = append(.extraValues, columnValue{
			column: ,
			value:  schema.SafeQuery(, ),
		})
	}
}

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

type setQuery struct {
	set []schema.QueryWithArgs
}

func ( *setQuery) ( schema.QueryWithArgs) {
	.set = append(.set, )
}

func ( setQuery) ( schema.Formatter,  []byte) ( []byte,  error) {
	for ,  := range .set {
		if  > 0 {
			 = append(, ", "...)
		}
		,  = .AppendQuery(, )
		if  != nil {
			return nil, 
		}
	}
	return , nil
}

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

type cascadeQuery struct {
	restrict bool
}

func ( cascadeQuery) ( schema.Formatter,  []byte) []byte {
	if !.HasFeature(feature.TableCascade) {
		return 
	}
	if .restrict {
		 = append(, " RESTRICT"...)
	} else {
		 = append(, " CASCADE"...)
	}
	return 
}