package orm

import (
	
	
	
	

	
)

type SelectQuery struct {
	q     *Query
	count string
}

var (
	_ QueryAppender = (*SelectQuery)(nil)
	_ QueryCommand  = (*SelectQuery)(nil)
)

func ( *Query) *SelectQuery {
	return &SelectQuery{
		q: ,
	}
}

func ( *SelectQuery) () string {
	,  := .AppendQuery(defaultFmter, nil)
	if  != nil {
		panic()
	}
	return string()
}

func ( *SelectQuery) () QueryOp {
	return SelectOp
}

func ( *SelectQuery) () QueryCommand {
	return &SelectQuery{
		q:     .q.Clone(),
		count: .count,
	}
}

func ( *SelectQuery) () *Query {
	return .q
}

func ( *SelectQuery) ( []byte) ([]byte, error) {
	return .AppendQuery(dummyFormatter{}, )
}

func ( *SelectQuery) ( QueryFormatter,  []byte) ( []byte,  error) { //nolint:gocyclo
	if .q.stickyErr != nil {
		return nil, .q.stickyErr
	}

	 := .count != "" && (len(.q.group) > 0 || .isDistinct())
	if  {
		 = append(, `WITH "_count_wrapper" AS (`...)
	}

	if len(.q.with) > 0 {
		,  = .q.appendWith(, )
		if  != nil {
			return nil, 
		}
	}

	if len(.q.union) > 0 {
		 = append(, '(')
	}

	 = append(, "SELECT "...)

	if len(.q.distinctOn) > 0 {
		 = append(, "DISTINCT ON ("...)
		for ,  := range .q.distinctOn {
			if  > 0 {
				 = append(, ", "...)
			}
			,  = .AppendQuery(, )
		}
		 = append(, ") "...)
	} else if .q.distinctOn != nil {
		 = append(, "DISTINCT "...)
	}

	if .count != "" && ! {
		 = append(, .count...)
	} else {
		,  = .appendColumns(, )
		if  != nil {
			return nil, 
		}
	}

	if .q.hasTables() {
		 = append(, " FROM "...)
		,  = .appendTables(, )
		if  != nil {
			return nil, 
		}
	}

	 = .q.forEachHasOneJoin(func( *join) error {
		 = append(, ' ')
		,  = .appendHasOneJoin(, , .q)
		return 
	})
	if  != nil {
		return nil, 
	}

	for ,  := range .q.joins {
		,  = .AppendQuery(, )
		if  != nil {
			return nil, 
		}
	}

	if len(.q.where) > 0 || .q.isSoftDelete() {
		 = append(, " WHERE "...)
		,  = .q.appendWhere(, )
		if  != nil {
			return nil, 
		}
	}

	if len(.q.group) > 0 {
		 = append(, " GROUP BY "...)
		for ,  := range .q.group {
			if  > 0 {
				 = append(, ", "...)
			}
			,  = .AppendQuery(, )
			if  != nil {
				return nil, 
			}
		}
	}

	if len(.q.having) > 0 {
		 = append(, " HAVING "...)
		for ,  := range .q.having {
			if  > 0 {
				 = append(, " AND "...)
			}
			 = append(, '(')
			,  = .AppendQuery(, )
			if  != nil {
				return nil, 
			}
			 = append(, ')')
		}
	}

	if .count == "" {
		if len(.q.order) > 0 {
			 = append(, " ORDER BY "...)
			for ,  := range .q.order {
				if  > 0 {
					 = append(, ", "...)
				}
				,  = .AppendQuery(, )
				if  != nil {
					return nil, 
				}
			}
		}

		if .q.limit != 0 {
			 = append(, " LIMIT "...)
			 = strconv.AppendInt(, int64(.q.limit), 10)
		}

		if .q.offset != 0 {
			 = append(, " OFFSET "...)
			 = strconv.AppendInt(, int64(.q.offset), 10)
		}

		if .q.selFor != nil {
			 = append(, " FOR "...)
			,  = .q.selFor.AppendQuery(, )
			if  != nil {
				return nil, 
			}
		}
	} else if  {
		 = append(, `) SELECT `...)
		 = append(, .count...)
		 = append(, ` FROM "_count_wrapper"`...)
	}

	if len(.q.union) > 0 {
		 = append(, ")"...)

		for ,  := range .q.union {
			 = append(, .expr...)
			 = append(, '(')
			,  = .query.AppendQuery(, )
			if  != nil {
				return nil, 
			}
			 = append(, ")"...)
		}
	}

	return , .q.stickyErr
}

func ( SelectQuery) ( QueryFormatter,  []byte) ( []byte,  error) {
	 := len()

	switch {
	case .q.columns != nil:
		,  = .q.appendColumns(, )
		if  != nil {
			return nil, 
		}
	case .q.hasExplicitTableModel():
		 := .q.tableModel.Table()
		if len(.Fields) > 10 && isTemplateFormatter() {
			 = append(, .Alias...)
			 = append(, '.')
			 = types.AppendString(, fmt.Sprintf("%d columns", len(.Fields)), 2)
		} else {
			 = appendColumns(, .Alias, .Fields)
		}
	default:
		 = append(, '*')
	}

	 = .q.forEachHasOneJoin(func( *join) error {
		if len() !=  {
			 = append(, ", "...)
			 = len()
		}

		 = .appendHasOneColumns()
		return nil
	})
	if  != nil {
		return nil, 
	}

	 = bytes.TrimSuffix(, []byte(", "))

	return , nil
}

func ( *SelectQuery) () bool {
	if .q.distinctOn != nil {
		return true
	}
	for ,  := range .q.columns {
		,  := .(*SafeQueryAppender)
		if  {
			if strings.Contains(.query, "DISTINCT") ||
				strings.Contains(.query, "distinct") {
				return true
			}
		}
	}
	return false
}

func ( *SelectQuery) ( QueryFormatter,  []byte) ( []byte,  error) {
	 := .q.tables

	if .q.modelHasTableName() {
		 := .q.tableModel.Table()
		 = .FormatQuery(, string(.SQLNameForSelects))
		if .Alias != "" {
			 = append(, " AS "...)
			 = append(, .Alias...)
		}

		if len() > 0 {
			 = append(, ", "...)
		}
	} else if len() > 0 {
		,  = [0].AppendQuery(, )
		if  != nil {
			return nil, 
		}
		if .q.modelHasTableAlias() {
			 = append(, " AS "...)
			 = append(, .q.tableModel.Table().Alias...)
		}

		 = [1:]
		if len() > 0 {
			 = append(, ", "...)
		}
	}

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

	return , nil
}

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

type joinQuery struct {
	join *SafeQueryAppender
	on   []*condAppender
}

func ( *joinQuery) ( *condAppender) {
	.on = append(.on, )
}

func ( *joinQuery) ( QueryFormatter,  []byte) ( []byte,  error) {
	 = append(, ' ')

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

	if len(.on) > 0 {
		 = append(, " ON "...)
		for ,  := range .on {
			if  > 0 {
				 = .AppendSep()
			}
			,  = .AppendQuery(, )
			if  != nil {
				return nil, 
			}
		}
	}

	return , nil
}