168 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			168 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package govaluate
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"regexp"
 | |
| 	"time"
 | |
| )
 | |
| 
 | |
| /*
 | |
| 	Returns a string representing this expression as if it were written in SQL.
 | |
| 	This function assumes that all parameters exist within the same table, and that the table essentially represents
 | |
| 	a serialized object of some sort (e.g., hibernate).
 | |
| 	If your data model is more normalized, you may need to consider iterating through each actual token given by `Tokens()`
 | |
| 	to create your query.
 | |
| 
 | |
| 	Boolean values are considered to be "1" for true, "0" for false.
 | |
| 
 | |
| 	Times are formatted according to this.QueryDateFormat.
 | |
| */
 | |
| func (this EvaluableExpression) ToSQLQuery() (string, error) {
 | |
| 
 | |
| 	var stream *tokenStream
 | |
| 	var transactions *expressionOutputStream
 | |
| 	var transaction string
 | |
| 	var err error
 | |
| 
 | |
| 	stream = newTokenStream(this.tokens)
 | |
| 	transactions = new(expressionOutputStream)
 | |
| 
 | |
| 	for stream.hasNext() {
 | |
| 
 | |
| 		transaction, err = this.findNextSQLString(stream, transactions)
 | |
| 		if err != nil {
 | |
| 			return "", err
 | |
| 		}
 | |
| 
 | |
| 		transactions.add(transaction)
 | |
| 	}
 | |
| 
 | |
| 	return transactions.createString(" "), nil
 | |
| }
 | |
| 
 | |
| func (this EvaluableExpression) findNextSQLString(stream *tokenStream, transactions *expressionOutputStream) (string, error) {
 | |
| 
 | |
| 	var token ExpressionToken
 | |
| 	var ret string
 | |
| 
 | |
| 	token = stream.next()
 | |
| 
 | |
| 	switch token.Kind {
 | |
| 
 | |
| 	case STRING:
 | |
| 		ret = fmt.Sprintf("'%v'", token.Value)
 | |
| 	case PATTERN:
 | |
| 		ret = fmt.Sprintf("'%s'", token.Value.(*regexp.Regexp).String())
 | |
| 	case TIME:
 | |
| 		ret = fmt.Sprintf("'%s'", token.Value.(time.Time).Format(this.QueryDateFormat))
 | |
| 
 | |
| 	case LOGICALOP:
 | |
| 		switch logicalSymbols[token.Value.(string)] {
 | |
| 
 | |
| 		case AND:
 | |
| 			ret = "AND"
 | |
| 		case OR:
 | |
| 			ret = "OR"
 | |
| 		}
 | |
| 
 | |
| 	case BOOLEAN:
 | |
| 		if token.Value.(bool) {
 | |
| 			ret = "1"
 | |
| 		} else {
 | |
| 			ret = "0"
 | |
| 		}
 | |
| 
 | |
| 	case VARIABLE:
 | |
| 		ret = fmt.Sprintf("[%s]", token.Value.(string))
 | |
| 
 | |
| 	case NUMERIC:
 | |
| 		ret = fmt.Sprintf("%g", token.Value.(float64))
 | |
| 
 | |
| 	case COMPARATOR:
 | |
| 		switch comparatorSymbols[token.Value.(string)] {
 | |
| 
 | |
| 		case EQ:
 | |
| 			ret = "="
 | |
| 		case NEQ:
 | |
| 			ret = "<>"
 | |
| 		case REQ:
 | |
| 			ret = "RLIKE"
 | |
| 		case NREQ:
 | |
| 			ret = "NOT RLIKE"
 | |
| 		default:
 | |
| 			ret = fmt.Sprintf("%s", token.Value.(string))
 | |
| 		}
 | |
| 
 | |
| 	case TERNARY:
 | |
| 
 | |
| 		switch ternarySymbols[token.Value.(string)] {
 | |
| 
 | |
| 		case COALESCE:
 | |
| 
 | |
| 			left := transactions.rollback()
 | |
| 			right, err := this.findNextSQLString(stream, transactions)
 | |
| 			if err != nil {
 | |
| 				return "", err
 | |
| 			}
 | |
| 
 | |
| 			ret = fmt.Sprintf("COALESCE(%v, %v)", left, right)
 | |
| 		case TERNARY_TRUE:
 | |
| 			fallthrough
 | |
| 		case TERNARY_FALSE:
 | |
| 			return "", errors.New("Ternary operators are unsupported in SQL output")
 | |
| 		}
 | |
| 	case PREFIX:
 | |
| 		switch prefixSymbols[token.Value.(string)] {
 | |
| 
 | |
| 		case INVERT:
 | |
| 			ret = fmt.Sprintf("NOT")
 | |
| 		default:
 | |
| 
 | |
| 			right, err := this.findNextSQLString(stream, transactions)
 | |
| 			if err != nil {
 | |
| 				return "", err
 | |
| 			}
 | |
| 
 | |
| 			ret = fmt.Sprintf("%s%s", token.Value.(string), right)
 | |
| 		}
 | |
| 	case MODIFIER:
 | |
| 
 | |
| 		switch modifierSymbols[token.Value.(string)] {
 | |
| 
 | |
| 		case EXPONENT:
 | |
| 
 | |
| 			left := transactions.rollback()
 | |
| 			right, err := this.findNextSQLString(stream, transactions)
 | |
| 			if err != nil {
 | |
| 				return "", err
 | |
| 			}
 | |
| 
 | |
| 			ret = fmt.Sprintf("POW(%s, %s)", left, right)
 | |
| 		case MODULUS:
 | |
| 
 | |
| 			left := transactions.rollback()
 | |
| 			right, err := this.findNextSQLString(stream, transactions)
 | |
| 			if err != nil {
 | |
| 				return "", err
 | |
| 			}
 | |
| 
 | |
| 			ret = fmt.Sprintf("MOD(%s, %s)", left, right)
 | |
| 		default:
 | |
| 			ret = fmt.Sprintf("%s", token.Value.(string))
 | |
| 		}
 | |
| 	case CLAUSE:
 | |
| 		ret = "("
 | |
| 	case CLAUSE_CLOSE:
 | |
| 		ret = ")"
 | |
| 	case SEPARATOR:
 | |
| 		ret = ","
 | |
| 
 | |
| 	default:
 | |
| 		errorMsg := fmt.Sprintf("Unrecognized query token '%s' of kind '%s'", token.Value, token.Kind)
 | |
| 		return "", errors.New(errorMsg)
 | |
| 	}
 | |
| 
 | |
| 	return ret, nil
 | |
| }
 |