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 }