github.com/aacfactory/fns-contrib/databases/sql@v1.2.84/dac/specifications/predicate.go (about)

     1  package specifications
     2  
     3  import (
     4  	"bytes"
     5  	"database/sql"
     6  	"fmt"
     7  	"github.com/aacfactory/errors"
     8  	"github.com/aacfactory/fns-contrib/databases/sql/dac/conditions"
     9  	"github.com/aacfactory/fns/commons/bytex"
    10  	"github.com/valyala/bytebufferpool"
    11  	"io"
    12  	"strings"
    13  )
    14  
    15  type Predicate struct {
    16  	conditions.Predicate
    17  }
    18  
    19  func (p Predicate) Render(ctx Context, w io.Writer) (argument []any, err error) {
    20  	column, hasColumn := ctx.Localization(p.Field)
    21  	if !hasColumn {
    22  		err = errors.Warning("sql: predicate render failed").WithCause(fmt.Errorf("%s was not found in localization", p.Field))
    23  		return
    24  	}
    25  	_, _ = w.Write(bytex.FromString(column[0]))
    26  	_, _ = w.Write(SPACE)
    27  	_, _ = w.Write(bytex.FromString(p.Operator.String()))
    28  	_, _ = w.Write(SPACE)
    29  
    30  	switch expr := p.Expression.(type) {
    31  	case conditions.Literal:
    32  		_, _ = w.Write(bytex.FromString(expr.String()))
    33  		break
    34  	case sql.NamedArg:
    35  		_, _ = w.Write(AT)
    36  		_, _ = w.Write(bytex.FromString(expr.Name))
    37  		argument = append(argument, expr)
    38  		break
    39  	case conditions.QueryExpr:
    40  		sub, subErr := QueryExpr{expr}.Render(ctx, w)
    41  		if subErr != nil {
    42  			err = errors.Warning("sql: predicate render failed").WithCause(subErr)
    43  			return
    44  		}
    45  		argument = append(argument, sub...)
    46  		break
    47  	case []any:
    48  		if p.Operator != conditions.BETWEEN && p.Operator != conditions.IN && p.Operator != conditions.NOTIN {
    49  			err = errors.Warning("sql: predicate render failed").WithCause(fmt.Errorf("%s only can has one expression", p.Field))
    50  			return
    51  		}
    52  		exprLen := len(expr)
    53  		if exprLen == 0 {
    54  			err = errors.Warning("sql: predicate render failed").WithCause(fmt.Errorf("%s only can has no expression", p.Field))
    55  			return
    56  		}
    57  		if exprLen == 1 {
    58  			queryExpr, isQueryExpr := expr[0].(QueryExpr)
    59  			if isQueryExpr {
    60  				sub, subErr := queryExpr.Render(ctx, w)
    61  				if subErr != nil {
    62  					err = errors.Warning("sql: predicate render failed").WithCause(subErr)
    63  					return
    64  				}
    65  				argument = append(argument, sub...)
    66  				break
    67  			}
    68  		}
    69  
    70  		exprs := make([][]byte, 0, len(expr))
    71  		for _, e := range expr {
    72  			switch se := e.(type) {
    73  			case conditions.Literal:
    74  				exprs = append(exprs, bytex.FromString(se.String()))
    75  				break
    76  			case sql.NamedArg:
    77  				err = errors.Warning("sql: predicate render failed").WithCause(fmt.Errorf("%s only can has named arg", p.Field))
    78  				return
    79  			case conditions.QueryExpr:
    80  				sbb := bytebufferpool.Get()
    81  				sub, subErr := QueryExpr{se}.Render(ctx, sbb)
    82  				if subErr != nil {
    83  					bytebufferpool.Put(sbb)
    84  					err = errors.Warning("sql: predicate render failed").WithCause(subErr)
    85  					return
    86  				}
    87  				subQuery := sbb.String()
    88  				bytebufferpool.Put(sbb)
    89  				if len(expr) == 1 {
    90  					subQuery = subQuery[strings.IndexByte(subQuery, '(')+1 : strings.LastIndexByte(subQuery, ')')]
    91  				}
    92  				exprs = append(exprs, bytex.FromString(subQuery))
    93  				argument = append(argument, sub...)
    94  				break
    95  			default:
    96  				exprs = append(exprs, bytex.FromString(ctx.NextQueryPlaceholder()))
    97  				argument = append(argument, se)
    98  				break
    99  			}
   100  		}
   101  
   102  		_, _ = w.Write(LB)
   103  		_, _ = w.Write(bytes.Join(exprs, COMMA))
   104  		_, _ = w.Write(RB)
   105  		break
   106  	default:
   107  		_, _ = w.Write(bytex.FromString(ctx.NextQueryPlaceholder()))
   108  		argument = append(argument, expr)
   109  		break
   110  	}
   111  
   112  	return
   113  }