surrealpatch/sql/string.go
2017-03-02 14:38:56 +00:00

775 lines
15 KiB
Go

// Copyright © 2016 Abcum Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package sql
import (
"encoding/json"
"fmt"
"strings"
"time"
)
func orNil(v interface{}) string {
switch v.(type) {
case nil:
return ""
default:
return fmt.Sprint(v)
}
}
func stringIf(b bool, v interface{}) string {
switch b {
case false:
return ""
default:
return fmt.Sprint(v)
}
}
func padToken(t Token) string {
switch t {
case OR, AND:
fallthrough
case IN, IS, CONTAINS:
fallthrough
case CONTAINSALL, CONTAINSNONE, CONTAINSSOME:
fallthrough
case ALLCONTAINEDIN, NONECONTAINEDIN, SOMECONTAINEDIN:
return fmt.Sprintf(" %v ", t)
default:
return fmt.Sprintf("%v", t)
}
}
func toQuote(s string) bool {
for _, c := range s {
switch {
case c >= 'a' && c <= 'z':
continue
case c >= 'A' && c <= 'Z':
continue
case c >= '0' && c <= '9':
continue
case c == '[', c == ']':
continue
case c == '-', c == '.':
continue
case c == '*':
continue
default:
return true
}
}
return false
}
func stringFromBool(v bool, y, n string) string {
switch v {
case false:
return n
default:
return y
}
}
func stringFromString(v string, y, n string) string {
switch v {
case "":
return n
default:
return y
}
}
func stringFromInt(v int64, y, n string) string {
switch v {
case 0:
return n
default:
return y
}
}
func stringFromFloat(v float64, y, n string) string {
switch v {
case 0:
return n
default:
return y
}
}
func stringFromArray(v Array, y, n string) string {
switch len(v) {
case 0:
return n
default:
return y
}
}
func stringFromSlice(v []interface{}, y, n string) string {
switch len(v) {
case 0:
return n
default:
return y
}
}
func stringFromIdent(v *Ident, y, n string) string {
switch v {
case nil:
return n
default:
return y
}
}
func stringFromInterface(v interface{}, y, n string) string {
switch v {
case nil:
return n
default:
return y
}
}
func stringFromDuration(v time.Duration, y, n string) string {
switch v {
case 0:
return n
default:
return y
}
}
// ---------------------------------------------
// Statements
// ---------------------------------------------
func (this BeginStatement) String() string {
return "BEGIN TRANSACTION"
}
func (this CancelStatement) String() string {
return "CANCEL TRANSACTION"
}
func (this CommitStatement) String() string {
return "COMMIT TRANSACTION"
}
func (this UseStatement) String() string {
switch {
case len(this.NS) == 0:
return fmt.Sprintf("USE DB %v", this.DB)
case len(this.DB) == 0:
return fmt.Sprintf("USE NS %v", this.NS)
default:
return fmt.Sprintf("USE NS %v DB %v", this.NS, this.DB)
}
}
func (this InfoStatement) String() string {
switch this.Kind {
case NAMESPACE:
return fmt.Sprintf("INFO FOR NAMESPACE")
case DATABASE:
return fmt.Sprintf("INFO FOR DATABASE")
default:
return fmt.Sprintf("INFO FOR TABLE %v", this.What)
}
}
func (this LetStatement) String() string {
return fmt.Sprintf("LET %v = %v",
this.Name,
this.What,
)
}
func (this ReturnStatement) String() string {
return fmt.Sprintf("RETURN %v",
this.What,
)
}
func (this SelectStatement) String() string {
return fmt.Sprintf("SELECT %v FROM %v%v%v%v%v%v%v%v",
this.Expr,
this.What,
stringFromInterface(this.Cond, fmt.Sprintf(" WHERE %v", this.Cond), ""),
this.Group,
this.Order,
stringFromInterface(this.Limit, fmt.Sprintf(" LIMIT %v", this.Limit), ""),
stringFromInterface(this.Start, fmt.Sprintf(" START %v", this.Start), ""),
stringFromInterface(this.Version, fmt.Sprintf(" VERSION %v", this.Version), ""),
stringFromDuration(this.Timeout, fmt.Sprintf(" TIMEOUT %v", this.Timeout.String()), ""),
)
}
func (this CreateStatement) String() string {
return fmt.Sprintf("CREATE %v%v RETURN %v%v",
this.What,
this.Data,
this.Echo,
stringFromDuration(this.Timeout, fmt.Sprintf(" TIMEOUT %v", this.Timeout.String()), ""),
)
}
func (this UpdateStatement) String() string {
return fmt.Sprintf("CREATE %v%v%v RETURN %v%v",
this.What,
this.Data,
this.Cond,
this.Echo,
stringFromDuration(this.Timeout, fmt.Sprintf(" TIMEOUT %v", this.Timeout.String()), ""),
)
}
func (this DeleteStatement) String() string {
return fmt.Sprintf("DELETE %v%v%v RETURN %v%v",
stringFromBool(this.Hard, "AND EXPUNGE ", ""),
this.What,
this.Cond,
this.Echo,
stringFromDuration(this.Timeout, fmt.Sprintf(" TIMEOUT %v", this.Timeout.String()), ""),
)
}
func (this RelateStatement) String() string {
return fmt.Sprintf("RELATE %v FROM %v WITH %v%v%v RETURN %v%v",
this.Type,
this.From,
this.With,
this.Data,
stringFromBool(this.Uniq, " UNIQUE", ""),
this.Echo,
stringFromDuration(this.Timeout, fmt.Sprintf(" TIMEOUT %v", this.Timeout.String()), ""),
)
}
func (this DefineNamespaceStatement) String() string {
return fmt.Sprintf("DEFINE NAMESPACE %v",
this.Name,
)
}
func (this RemoveNamespaceStatement) String() string {
return fmt.Sprintf("REMOVE NAMESPACE %v",
this.Name,
)
}
func (this DefineDatabaseStatement) String() string {
return fmt.Sprintf("DEFINE DATABASE %v",
this.Name,
)
}
func (this RemoveDatabaseStatement) String() string {
return fmt.Sprintf("REMOVE DATABASE %v",
this.Name,
)
}
func (this DefineLoginStatement) String() string {
return fmt.Sprintf("DEFINE LOGIN %v ON %v PASSWORD ********",
this.User,
this.Kind,
)
}
func (this RemoveLoginStatement) String() string {
return fmt.Sprintf("REMOVE LOGIN %v ON %v",
this.User,
this.Kind,
)
}
func (this DefineTokenStatement) String() string {
return fmt.Sprintf("DEFINE TOKEN %v ON %v TYPE %v VALUE ********",
this.Name,
this.Kind,
this.Type,
)
}
func (this RemoveTokenStatement) String() string {
return fmt.Sprintf("REMOVE TOKEN %v ON %v",
this.Name,
this.Kind,
)
}
func (this DefineScopeStatement) String() string {
return fmt.Sprintf("DEFINE SCOPE %v SESSION %v SIGNUP AS (%v) SIGNIN AS (%v)",
this.Name,
this.Time,
this.Signup,
this.Signin,
)
}
func (this RemoveScopeStatement) String() string {
return fmt.Sprintf("REMOVE SCOPE %v",
this.Name,
)
}
func (this DefineTableStatement) String() string {
return fmt.Sprintf("DEFINE TABLE %v%v%v",
this.What,
stringFromBool(this.Full, " SCHEMAFULL", " SCHEMALESS"),
stringIf(this.Perm != nil, this.Perm),
)
}
func (this RemoveTableStatement) String() string {
return fmt.Sprintf("REMOVE TABLE %v",
this.What,
)
}
func (this DefineFieldStatement) String() string {
return fmt.Sprintf("DEFINE FIELD %v ON %v TYPE %v%v%v%v%v%v%v%v%v%v%v%v",
this.Name,
this.What,
this.Type,
stringFromFloat(this.Min, fmt.Sprintf(" MIN %v", this.Min), ""),
stringFromFloat(this.Max, fmt.Sprintf(" MAX %v", this.Max), ""),
stringFromArray(this.Enum, fmt.Sprintf(" ENUM %v", this.Enum), ""),
stringFromString(this.Code, fmt.Sprintf(" CODE \"%v\"", this.Code), ""),
stringFromString(this.Match, fmt.Sprintf(" MATCH /%v/", this.Match), ""),
stringFromInterface(this.Default, fmt.Sprintf(" DEFAULT %v", this.Default), ""),
stringFromBool(this.Notnull, " NOTNULL", ""),
stringFromBool(this.Readonly, " READONLY", ""),
stringFromBool(this.Validate, " VALIDATE", ""),
stringFromBool(this.Mandatory, " MANDATORY", ""),
stringIf(this.Perm != nil, this.Perm),
)
}
func (this RemoveFieldStatement) String() string {
return fmt.Sprintf("REMOVE FIELD %v ON %v",
this.Name,
this.What,
)
}
func (this DefineIndexStatement) String() string {
return fmt.Sprintf("DEFINE INDEX %v ON %v COLUMNS %v%v",
this.Name,
this.What,
this.Cols,
stringFromBool(this.Uniq, " UNIQUE", ""),
)
}
func (this RemoveIndexStatement) String() string {
return fmt.Sprintf("REMOVE INDEX %v",
this.Name,
)
}
func (this DefineViewStatement) String() string {
return fmt.Sprintf("DEFINE VIEW %v",
this.Name,
)
}
func (this RemoveViewStatement) String() string {
return fmt.Sprintf("REMOVE VIEW %v",
this.Name,
)
}
// ---------------------------------------------
// Literals
// ---------------------------------------------
func (this Exprs) String() string {
var m []string
for _, v := range this {
m = append(m, fmt.Sprintf("%v", v))
}
return strings.Join(m, ", ")
}
func (this All) String() string {
return "*"
}
func (this Any) String() string {
return "?"
}
func (this Asc) String() string {
return "ASC"
}
func (this Desc) String() string {
return "DESC"
}
func (this Null) String() string {
return "NULL"
}
func (this Void) String() string {
return "VOID"
}
func (this Empty) String() string {
return "EMPTY"
}
func (this Array) String() string {
out, _ := json.Marshal(this)
return string(out)
}
func (this Object) String() string {
out, _ := json.Marshal(this)
return string(out)
}
// ---------------------------------------------
// Field
// ---------------------------------------------
func (this Fields) String() string {
var m []string
for _, v := range this {
m = append(m, v.String())
}
return fmt.Sprintf("%v",
strings.Join(m, ", "),
)
}
func (this Field) String() string {
return fmt.Sprintf("%v%v",
this.Expr,
stringFromIdent(this.Alias, fmt.Sprintf(" AS %v", this.Alias), ""),
)
}
// ---------------------------------------------
// Group
// ---------------------------------------------
func (this Groups) String() string {
if len(this) == 0 {
return ""
}
var m []string
for _, v := range this {
m = append(m, v.String())
}
return fmt.Sprintf(" GROUP BY %v",
strings.Join(m, ", "),
)
}
func (this Group) String() string {
return fmt.Sprintf("%v",
this.Expr,
)
}
// ---------------------------------------------
// Order
// ---------------------------------------------
func (this Orders) String() string {
if len(this) == 0 {
return ""
}
var m []string
for _, v := range this {
m = append(m, v.String())
}
return fmt.Sprintf(" ORDER BY %v",
strings.Join(m, ", "),
)
}
func (this Order) String() string {
return fmt.Sprintf("%v %v",
this.Expr,
this.Dir,
)
}
// ---------------------------------------------
// Param
// ---------------------------------------------
func (this Params) String() string {
var m []string
for _, v := range this {
m = append(m, v.String())
}
return strings.Join(m, ", ")
}
func (this Param) String() string {
return fmt.Sprintf("$%v", this.ID)
}
// ---------------------------------------------
// Value
// ---------------------------------------------
func (this Values) String() string {
var m []string
for _, v := range this {
m = append(m, v.String())
}
return strings.Join(m, ", ")
}
func (this Value) String() string {
return fmt.Sprintf("\"%v\"", this.ID)
}
// ---------------------------------------------
// Ident
// ---------------------------------------------
func (this Idents) String() string {
var m []string
for _, v := range this {
m = append(m, v.String())
}
return strings.Join(m, ", ")
}
func (this Ident) String() string {
switch newToken(this.ID) {
case ILLEGAL:
if toQuote(this.ID) {
return fmt.Sprintf("`%v`", this.ID)
}
return fmt.Sprintf("%v", this.ID)
default:
return fmt.Sprintf("`%v`", this.ID)
}
}
// ---------------------------------------------
// Table
// ---------------------------------------------
func (this Tables) String() string {
var m []string
for _, v := range this {
m = append(m, v.String())
}
return strings.Join(m, ", ")
}
func (this Table) String() string {
switch newToken(this.TB) {
case ILLEGAL:
if toQuote(this.TB) {
return fmt.Sprintf("`%v`", this.TB)
}
return fmt.Sprintf("%v", this.TB)
default:
return fmt.Sprintf("`%v`", this.TB)
}
}
// ---------------------------------------------
// Thing
// ---------------------------------------------
func (this Things) String() string {
var m []string
for _, v := range this {
m = append(m, v.String())
}
return strings.Join(m, ", ")
}
func (this Thing) String() string {
tb := this.TB
if toQuote(fmt.Sprint(this.TB)) {
tb = fmt.Sprintf("{%v}", this.TB)
}
id := this.ID
if toQuote(fmt.Sprint(this.ID)) {
id = fmt.Sprintf("{%v}", this.ID)
}
return fmt.Sprintf("@%v:%v", tb, id)
}
// ---------------------------------------------
// Expressions
// ---------------------------------------------
func (this SubExpression) String() string {
return fmt.Sprintf("(%v)",
this.Expr,
)
}
func (this FuncExpression) String() string {
return fmt.Sprintf("%v()",
this.Name,
)
}
func (this ItemExpression) String() string {
return fmt.Sprintf("%v %v %v",
this.LHS,
this.Op,
this.RHS,
)
}
func (this BinaryExpression) String() string {
return fmt.Sprintf("%v%v%v",
this.LHS,
padToken(this.Op),
this.RHS,
)
}
func (this PathExpression) String() string {
var m []string
for _, v := range this.Expr {
m = append(m, fmt.Sprintf("%v", v))
}
return strings.Join(m, "")
}
func (this PartExpression) String() string {
return fmt.Sprintf("%v",
this.Part,
)
}
func (this JoinExpression) String() string {
return fmt.Sprintf("%v",
this.Join,
)
}
func (this SubpExpression) String() string {
return fmt.Sprintf("(%v%v%v)",
this.What,
stringFromIdent(this.Name, fmt.Sprintf(" AS %v", this.Name), ""),
stringFromInterface(this.Cond, fmt.Sprintf(" WHERE %v", this.Cond), ""),
)
}
func (this DataExpression) String() string {
var m []string
for _, v := range this.Data {
m = append(m, v.String())
}
return fmt.Sprintf(" SET %v",
strings.Join(m, ", "),
)
}
func (this DiffExpression) String() string {
return fmt.Sprintf(" DIFF %v",
this.Data,
)
}
func (this MergeExpression) String() string {
return fmt.Sprintf(" MERGE %v",
this.Data,
)
}
func (this ContentExpression) String() string {
return fmt.Sprintf(" CONTENT %v",
this.Data,
)
}
func (this PermExpression) String() string {
var s, c, u, d, r string
p := map[bool][]string{}
if v, ok := this.Select.(bool); ok {
s = stringFromBool(v, "FULL", "NONE")
p[v] = append(p[v], fmt.Sprintf("select"))
} else {
s = fmt.Sprintf("WHERE %v", this.Select)
}
if v, ok := this.Create.(bool); ok {
c = stringFromBool(v, "FULL", "NONE")
p[v] = append(p[v], fmt.Sprintf("create"))
} else {
c = fmt.Sprintf("WHERE %v", this.Create)
}
if v, ok := this.Update.(bool); ok {
u = stringFromBool(v, "FULL", "NONE")
p[v] = append(p[v], fmt.Sprintf("update"))
} else {
u = fmt.Sprintf("WHERE %v", this.Update)
}
if v, ok := this.Delete.(bool); ok {
d = stringFromBool(v, "FULL", "NONE")
p[v] = append(p[v], fmt.Sprintf("delete"))
} else {
d = fmt.Sprintf("WHERE %v", this.Delete)
}
if v, ok := this.Relate.(bool); ok {
r = stringFromBool(v, "FULL", "NONE")
p[v] = append(p[v], fmt.Sprintf("relate"))
} else {
r = fmt.Sprintf("WHERE %v", this.Relate)
}
if len(p[true]) == 5 {
return fmt.Sprintf(" PERMISSIONS FULL")
}
if len(p[false]) == 5 {
return fmt.Sprintf(" PERMISSIONS NONE")
}
if len(p[true])+len(p[false]) == 5 {
return fmt.Sprintf(" PERMISSIONS FOR %v FULL FOR %v NONE",
strings.Join(p[true], ", "),
strings.Join(p[false], ", "),
)
}
return fmt.Sprintf(" PERMISSIONS%v%v%v%v%v",
fmt.Sprintf(" FOR select %v", s),
fmt.Sprintf(" FOR create %v", c),
fmt.Sprintf(" FOR update %v", u),
fmt.Sprintf(" FOR delete %v", d),
fmt.Sprintf(" FOR relate %v", r),
)
}