package squirrel

import (
	
	
	
	
	
	
)

Portable true/false literals.
	sqlTrue  = "(1=1)"
	sqlFalse = "(1=0)"
)

type expr struct {
	sql  string
	args []interface{}
}
Expr builds an expression from a SQL fragment and arguments. Ex: Expr("FROM_UNIXTIME(?)", t)
func ( string,  ...interface{}) Sqlizer {
	return expr{sql: , args: }
}

func ( expr) () ( string,  []interface{},  error) {
	 := true
	for ,  := range .args {
		if ,  := .(Sqlizer);  {
			 = false
		}
	}
	if  {
		return .sql, .args, nil
	}

	 := &bytes.Buffer{}
	 := .args
	 := .sql

	var  string
	var  []interface{}

	for  == nil && len() > 0 && len() > 0 {
		 := strings.Index(, "?")
no more placeholders
			break
		}
escaped "??"; append it and step past
			.WriteString([:+2])
			 = [+2:]
			continue
		}

sqlizer argument; expand it and append the result
			, ,  = .ToSql()
			.WriteString([:])
			.WriteString()
			 = append(, ...)
normal argument; append it and the placeholder
			.WriteString([:+1])
			 = append(, [0])
		}
step past the argument and placeholder
		 = [1:]
		 = [+1:]
	}
append the remaining sql and arguments
	.WriteString()
	return .String(), append(, ...), 
}

type concatExpr []interface{}

func ( concatExpr) () ( string,  []interface{},  error) {
	for ,  := range  {
		switch p := .(type) {
		case string:
			 += 
		case Sqlizer:
			, ,  := .ToSql()
			if  != nil {
				return "", nil, 
			}
			 += 
			 = append(, ...)
		default:
			return "", nil, fmt.Errorf("%#v is not a string or Sqlizer", )
		}
	}
	return
}
ConcatExpr builds an expression by concatenating strings and other expressions. Ex: name_expr := Expr("CONCAT(?, ' ', ?)", firstName, lastName) ConcatExpr("COALESCE(full_name,", name_expr, ")")
func ( ...interface{}) concatExpr {
	return concatExpr()
}
aliasExpr helps to alias part of SQL query generated with underlying "expr"
type aliasExpr struct {
	expr  Sqlizer
	alias string
}
Alias allows to define alias for column in SelectBuilder. Useful when column is defined as complex expression like IF or CASE Ex: .Column(Alias(caseStmt, "case_column"))
func ( Sqlizer,  string) aliasExpr {
	return aliasExpr{, }
}

func ( aliasExpr) () ( string,  []interface{},  error) {
	, ,  = .expr.ToSql()
	if  == nil {
		 = fmt.Sprintf("(%s) AS %s", , .alias)
	}
	return
}
Eq is syntactic sugar for use with Where/Having/Set methods.
type Eq map[string]interface{}

func ( Eq) ( bool) ( string,  []interface{},  error) {
Empty Sql{} evaluates to true.
		 = sqlTrue
		return
	}

	var (
		       []string
		    = "="
		       = "IN"
		     = "IS"
		 = sqlFalse
	)

	if  {
		 = "<>"
		 = "NOT IN"
		 = "IS NOT"
		 = sqlTrue
	}

	 := getSortedKeys()
	for ,  := range  {
		var  string
		 := []

		switch v := .(type) {
		case driver.Valuer:
			if ,  = .Value();  != nil {
				return
			}
		}

		 := reflect.ValueOf()
		if .Kind() == reflect.Ptr {
			if .IsNil() {
				 = nil
			} else {
				 = .Elem().Interface()
			}
		}

		if  == nil {
			 = fmt.Sprintf("%s %s NULL", , )
		} else {
			if isListType() {
				 := reflect.ValueOf()
				if .Len() == 0 {
					 = 
					if  == nil {
						 = []interface{}{}
					}
				} else {
					for  := 0;  < .Len(); ++ {
						 = append(, .Index().Interface())
					}
					 = fmt.Sprintf("%s %s (%s)", , , Placeholders(.Len()))
				}
			} else {
				 = fmt.Sprintf("%s %s ?", , )
				 = append(, )
			}
		}
		 = append(, )
	}
	 = strings.Join(, " AND ")
	return
}

func ( Eq) () ( string,  []interface{},  error) {
	return .toSQL(false)
}
NotEq is syntactic sugar for use with Where/Having/Set methods. Ex: .Where(NotEq{"id": 1}) == "id <> 1"
type NotEq Eq

func ( NotEq) () ( string,  []interface{},  error) {
	return Eq().toSQL(true)
}
Like is syntactic sugar for use with LIKE conditions. Ex: .Where(Like{"name": "%irrel"})
type Like map[string]interface{}

func ( Like) ( string) ( string,  []interface{},  error) {
	var  []string
	for ,  := range  {
		 := ""

		switch v := .(type) {
		case driver.Valuer:
			if ,  = .Value();  != nil {
				return
			}
		}

		if  == nil {
			 = fmt.Errorf("cannot use null with like operators")
			return
		} else {
			if isListType() {
				 = fmt.Errorf("cannot use array or slice with like operators")
				return
			} else {
				 = fmt.Sprintf("%s %s ?", , )
				 = append(, )
			}
		}
		 = append(, )
	}
	 = strings.Join(, " AND ")
	return
}

func ( Like) () ( string,  []interface{},  error) {
	return .toSql("LIKE")
}
NotLike is syntactic sugar for use with LIKE conditions. Ex: .Where(NotLike{"name": "%irrel"})
type NotLike Like

func ( NotLike) () ( string,  []interface{},  error) {
	return Like().toSql("NOT LIKE")
}
ILike is syntactic sugar for use with ILIKE conditions. Ex: .Where(ILike{"name": "sq%"})
type ILike Like

func ( ILike) () ( string,  []interface{},  error) {
	return Like().toSql("ILIKE")
}
NotILike is syntactic sugar for use with ILIKE conditions. Ex: .Where(NotILike{"name": "sq%"})
type NotILike Like

func ( NotILike) () ( string,  []interface{},  error) {
	return Like().toSql("NOT ILIKE")
}
Lt is syntactic sugar for use with Where/Having/Set methods. Ex: .Where(Lt{"id": 1})
type Lt map[string]interface{}

func ( Lt) (,  bool) ( string,  []interface{},  error) {
	var (
		 []string
		   = "<"
	)

	if  {
		 = ">"
	}

	if  {
		 = fmt.Sprintf("%s%s", , "=")
	}

	 := getSortedKeys()
	for ,  := range  {
		var  string
		 := []

		switch v := .(type) {
		case driver.Valuer:
			if ,  = .Value();  != nil {
				return
			}
		}

		if  == nil {
			 = fmt.Errorf("cannot use null with less than or greater than operators")
			return
		}
		if isListType() {
			 = fmt.Errorf("cannot use array or slice with less than or greater than operators")
			return
		}
		 = fmt.Sprintf("%s %s ?", , )
		 = append(, )

		 = append(, )
	}
	 = strings.Join(, " AND ")
	return
}

func ( Lt) () ( string,  []interface{},  error) {
	return .toSql(false, false)
}
LtOrEq is syntactic sugar for use with Where/Having/Set methods. Ex: .Where(LtOrEq{"id": 1}) == "id <= 1"
type LtOrEq Lt

func ( LtOrEq) () ( string,  []interface{},  error) {
	return Lt().toSql(false, true)
}
Gt is syntactic sugar for use with Where/Having/Set methods. Ex: .Where(Gt{"id": 1}) == "id > 1"
type Gt Lt

func ( Gt) () ( string,  []interface{},  error) {
	return Lt().toSql(true, false)
}
GtOrEq is syntactic sugar for use with Where/Having/Set methods. Ex: .Where(GtOrEq{"id": 1}) == "id >= 1"
type GtOrEq Lt

func ( GtOrEq) () ( string,  []interface{},  error) {
	return Lt().toSql(true, true)
}

type conj []Sqlizer

func ( conj) (,  string) ( string,  []interface{},  error) {
	if len() == 0 {
		return , []interface{}{}, nil
	}
	var  []string
	for ,  := range  {
		, ,  := .ToSql()
		if  != nil {
			return "", nil, 
		}
		if  != "" {
			 = append(, )
			 = append(, ...)
		}
	}
	if len() > 0 {
		 = fmt.Sprintf("(%s)", strings.Join(, ))
	}
	return
}
And conjunction Sqlizers
type And conj

func ( And) () (string, []interface{}, error) {
	return conj().join(" AND ", sqlTrue)
}
Or conjunction Sqlizers
type Or conj

func ( Or) () (string, []interface{}, error) {
	return conj().join(" OR ", sqlFalse)
}

func ( map[string]interface{}) []string {
	 := make([]string, 0, len())
	for  := range  {
		 = append(, )
	}
	sort.Strings()
	return 
}

func ( interface{}) bool {
	if driver.IsValue() {
		return false
	}
	 := reflect.ValueOf()
	return .Kind() == reflect.Array || .Kind() == reflect.Slice