/vendor/github.com/Knetic/govaluate/EvaluableExpression_sql.go

https://bitbucket.org/jyotiswarp/ppc · Go · 167 lines · 120 code · 36 blank · 11 comment · 19 complexity · 98e28ed7846e92034762a4c23dce2f28 MD5 · raw file

  1. package govaluate
  2. import (
  3. "errors"
  4. "fmt"
  5. "regexp"
  6. "time"
  7. )
  8. /*
  9. Returns a string representing this expression as if it were written in SQL.
  10. This function assumes that all parameters exist within the same table, and that the table essentially represents
  11. a serialized object of some sort (e.g., hibernate).
  12. If your data model is more normalized, you may need to consider iterating through each actual token given by `Tokens()`
  13. to create your query.
  14. Boolean values are considered to be "1" for true, "0" for false.
  15. Times are formatted according to this.QueryDateFormat.
  16. */
  17. func (this EvaluableExpression) ToSQLQuery() (string, error) {
  18. var stream *tokenStream
  19. var transactions *expressionOutputStream
  20. var transaction string
  21. var err error
  22. stream = newTokenStream(this.tokens)
  23. transactions = new(expressionOutputStream)
  24. for stream.hasNext() {
  25. transaction, err = this.findNextSQLString(stream, transactions)
  26. if err != nil {
  27. return "", err
  28. }
  29. transactions.add(transaction)
  30. }
  31. return transactions.createString(" "), nil
  32. }
  33. func (this EvaluableExpression) findNextSQLString(stream *tokenStream, transactions *expressionOutputStream) (string, error) {
  34. var token ExpressionToken
  35. var ret string
  36. token = stream.next()
  37. switch token.Kind {
  38. case STRING:
  39. ret = fmt.Sprintf("'%v'", token.Value)
  40. case PATTERN:
  41. ret = fmt.Sprintf("'%s'", token.Value.(*regexp.Regexp).String())
  42. case TIME:
  43. ret = fmt.Sprintf("'%s'", token.Value.(time.Time).Format(this.QueryDateFormat))
  44. case LOGICALOP:
  45. switch logicalSymbols[token.Value.(string)] {
  46. case AND:
  47. ret = "AND"
  48. case OR:
  49. ret = "OR"
  50. }
  51. case BOOLEAN:
  52. if token.Value.(bool) {
  53. ret = "1"
  54. } else {
  55. ret = "0"
  56. }
  57. case VARIABLE:
  58. ret = fmt.Sprintf("[%s]", token.Value.(string))
  59. case NUMERIC:
  60. ret = fmt.Sprintf("%g", token.Value.(float64))
  61. case COMPARATOR:
  62. switch comparatorSymbols[token.Value.(string)] {
  63. case EQ:
  64. ret = "="
  65. case NEQ:
  66. ret = "<>"
  67. case REQ:
  68. ret = "RLIKE"
  69. case NREQ:
  70. ret = "NOT RLIKE"
  71. default:
  72. ret = fmt.Sprintf("%s", token.Value.(string))
  73. }
  74. case TERNARY:
  75. switch ternarySymbols[token.Value.(string)] {
  76. case COALESCE:
  77. left := transactions.rollback()
  78. right, err := this.findNextSQLString(stream, transactions)
  79. if err != nil {
  80. return "", err
  81. }
  82. ret = fmt.Sprintf("COALESCE(%v, %v)", left, right)
  83. case TERNARY_TRUE:
  84. fallthrough
  85. case TERNARY_FALSE:
  86. return "", errors.New("Ternary operators are unsupported in SQL output")
  87. }
  88. case PREFIX:
  89. switch prefixSymbols[token.Value.(string)] {
  90. case INVERT:
  91. ret = fmt.Sprintf("NOT")
  92. default:
  93. right, err := this.findNextSQLString(stream, transactions)
  94. if err != nil {
  95. return "", err
  96. }
  97. ret = fmt.Sprintf("%s%s", token.Value.(string), right)
  98. }
  99. case MODIFIER:
  100. switch modifierSymbols[token.Value.(string)] {
  101. case EXPONENT:
  102. left := transactions.rollback()
  103. right, err := this.findNextSQLString(stream, transactions)
  104. if err != nil {
  105. return "", err
  106. }
  107. ret = fmt.Sprintf("POW(%s, %s)", left, right)
  108. case MODULUS:
  109. left := transactions.rollback()
  110. right, err := this.findNextSQLString(stream, transactions)
  111. if err != nil {
  112. return "", err
  113. }
  114. ret = fmt.Sprintf("MOD(%s, %s)", left, right)
  115. default:
  116. ret = fmt.Sprintf("%s", token.Value.(string))
  117. }
  118. case CLAUSE:
  119. ret = "("
  120. case CLAUSE_CLOSE:
  121. ret = ")"
  122. case SEPARATOR:
  123. ret = ","
  124. default:
  125. errorMsg := fmt.Sprintf("Unrecognized query token '%s' of kind '%s'", token.Value, token.Kind)
  126. return "", errors.New(errorMsg)
  127. }
  128. return ret, nil
  129. }