Add smart quote helper
This commit is contained in:
parent
65b80ddc13
commit
b171fd42ba
2 changed files with 26 additions and 88 deletions
strmangle
|
@ -7,6 +7,7 @@ package strmangle
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jinzhu/inflection"
|
"github.com/jinzhu/inflection"
|
||||||
|
@ -15,37 +16,29 @@ import (
|
||||||
var (
|
var (
|
||||||
idAlphabet = []byte("abcdefghijklmnopqrstuvwxyz")
|
idAlphabet = []byte("abcdefghijklmnopqrstuvwxyz")
|
||||||
uppercaseWords = []string{"id", "uid", "uuid", "guid", "ssn", "tz"}
|
uppercaseWords = []string{"id", "uid", "uuid", "guid", "ssn", "tz"}
|
||||||
|
smartQuoteRgx = regexp.MustCompile(`^(?i)"?[a-z_][_a-z0-9]*"?(\."?[_a-z][_a-z0-9]*"?)*$`)
|
||||||
)
|
)
|
||||||
|
|
||||||
type state int
|
|
||||||
type smartStack []state
|
|
||||||
|
|
||||||
const (
|
|
||||||
stateNothing = iota
|
|
||||||
stateSubExpression
|
|
||||||
stateFunction
|
|
||||||
stateIdentifier
|
|
||||||
)
|
|
||||||
|
|
||||||
func (stack *smartStack) push(s state) {
|
|
||||||
*stack = append(*stack, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (stack *smartStack) pop() state {
|
|
||||||
l := len(*stack)
|
|
||||||
if l == 0 {
|
|
||||||
return stateNothing
|
|
||||||
}
|
|
||||||
|
|
||||||
v := (*stack)[l-1]
|
|
||||||
*stack = (*stack)[:l-1]
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
// SmartQuote intelligently quotes identifiers in sql statements
|
// SmartQuote intelligently quotes identifiers in sql statements
|
||||||
func SmartQuote(s string) string {
|
func SmartQuote(s string) string {
|
||||||
// split on comma, treat as individual thing
|
if s == "null" {
|
||||||
return s
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
if m := smartQuoteRgx.MatchString(s); m != true {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
splits := strings.Split(s, ".")
|
||||||
|
for i, split := range splits {
|
||||||
|
if strings.HasPrefix(split, `"`) || strings.HasSuffix(split, `"`) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
splits[i] = fmt.Sprintf(`"%s"`, split)
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(splits, ".")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Identifier is a base conversion from Base 10 integers to Base 26
|
// Identifier is a base conversion from Base 10 integers to Base 26
|
||||||
|
|
|
@ -5,60 +5,6 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestStack(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
stack := smartStack{}
|
|
||||||
|
|
||||||
if stack.pop() != stateNothing {
|
|
||||||
t.Errorf("Expected state nothing for empty stack")
|
|
||||||
}
|
|
||||||
|
|
||||||
stack.push(stateFunction)
|
|
||||||
stack.push(stateSubExpression)
|
|
||||||
stack.push(stateNothing)
|
|
||||||
|
|
||||||
if len(stack) != 3 {
|
|
||||||
t.Errorf("Expected 3 state on stack, got %d", len(stack))
|
|
||||||
}
|
|
||||||
|
|
||||||
if r := stack.pop(); r != stateNothing {
|
|
||||||
t.Errorf("Expected stateNothing, got %v", r)
|
|
||||||
}
|
|
||||||
if len(stack) != 2 {
|
|
||||||
t.Errorf("Expected 2 state on stack, got %d", len(stack))
|
|
||||||
}
|
|
||||||
|
|
||||||
if r := stack.pop(); r != stateSubExpression {
|
|
||||||
t.Errorf("Expected stateSubExpression, got %v", r)
|
|
||||||
}
|
|
||||||
if len(stack) != 1 {
|
|
||||||
t.Errorf("Expected 1 state on stack, got %d", len(stack))
|
|
||||||
}
|
|
||||||
|
|
||||||
stack.push(stateSubExpression)
|
|
||||||
if len(stack) != 2 {
|
|
||||||
t.Errorf("Expected 2 state on stack, got %d", len(stack))
|
|
||||||
}
|
|
||||||
|
|
||||||
if r := stack.pop(); r != stateSubExpression {
|
|
||||||
t.Errorf("Expected stateSubExpression, got %v", r)
|
|
||||||
}
|
|
||||||
if len(stack) != 1 {
|
|
||||||
t.Errorf("Expected 1 state on stack, got %d", len(stack))
|
|
||||||
}
|
|
||||||
|
|
||||||
if r := stack.pop(); r != stateFunction {
|
|
||||||
t.Errorf("Expected stateFunction, got %v", r)
|
|
||||||
}
|
|
||||||
if len(stack) != 0 {
|
|
||||||
t.Errorf("Expected 0 state on stack, got %d", len(stack))
|
|
||||||
}
|
|
||||||
if stack.pop() != stateNothing {
|
|
||||||
t.Errorf("Expected state nothing for empty stack")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSmartQuote(t *testing.T) {
|
func TestSmartQuote(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
@ -66,15 +12,14 @@ func TestSmartQuote(t *testing.T) {
|
||||||
In string
|
In string
|
||||||
Out string
|
Out string
|
||||||
}{
|
}{
|
||||||
{In: `count(*) as thing, thing as stuff`, Out: `count(*) as thing, "thing" as stuff`},
|
|
||||||
{In: `select (select 1) as thing, thing as stuff`, Out: `select (select 1) as thing, "thing" as stuff`},
|
|
||||||
{
|
|
||||||
In: `select (select stuff as thing from thing where id=1 or name="thing") as stuff`,
|
|
||||||
Out: `select (select "stuff" as thing from thing where id=1 or name="thing") as stuff`,
|
|
||||||
},
|
|
||||||
{In: `thing`, Out: `"thing"`},
|
{In: `thing`, Out: `"thing"`},
|
||||||
{In: `thing, stuff`, Out: `"thing", "stuff"`},
|
{In: `null`, Out: `null`},
|
||||||
|
{In: `"thing"`, Out: `"thing"`},
|
||||||
{In: `*`, Out: `*`},
|
{In: `*`, Out: `*`},
|
||||||
|
{In: `thing.thing`, Out: `"thing"."thing"`},
|
||||||
|
{In: `"thing"."thing"`, Out: `"thing"."thing"`},
|
||||||
|
{In: `thing.thing.thing.thing`, Out: `"thing"."thing"."thing"."thing"`},
|
||||||
|
{In: `thing."thing".thing."thing"`, Out: `"thing"."thing"."thing"."thing"`},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
|
Loading…
Add table
Reference in a new issue