-
-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes go-gorm/sqlite#192.
- Loading branch information
Showing
6 changed files
with
192 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package gormlite | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
) | ||
|
||
type parseAllColumnsState int | ||
|
||
const ( | ||
parseAllColumnsState_NONE parseAllColumnsState = iota | ||
parseAllColumnsState_Beginning | ||
parseAllColumnsState_ReadingRawName | ||
parseAllColumnsState_ReadingQuotedName | ||
parseAllColumnsState_EndOfName | ||
parseAllColumnsState_State_End | ||
) | ||
|
||
func parseAllColumns(in string) ([]string, error) { | ||
s := []rune(in) | ||
columns := make([]string, 0) | ||
state := parseAllColumnsState_NONE | ||
quote := rune(0) | ||
name := make([]rune, 0) | ||
for i := 0; i < len(s); i++ { | ||
switch state { | ||
case parseAllColumnsState_NONE: | ||
if s[i] == '(' { | ||
state = parseAllColumnsState_Beginning | ||
} | ||
case parseAllColumnsState_Beginning: | ||
if isSpace(s[i]) { | ||
continue | ||
} | ||
if isQuote(s[i]) { | ||
state = parseAllColumnsState_ReadingQuotedName | ||
quote = s[i] | ||
continue | ||
} | ||
if s[i] == '[' { | ||
state = parseAllColumnsState_ReadingQuotedName | ||
quote = ']' | ||
continue | ||
} else if s[i] == ')' { | ||
return columns, fmt.Errorf("unexpected token: %s", string(s[i])) | ||
} | ||
state = parseAllColumnsState_ReadingRawName | ||
name = append(name, s[i]) | ||
case parseAllColumnsState_ReadingRawName: | ||
if isSeparator(s[i]) { | ||
state = parseAllColumnsState_Beginning | ||
columns = append(columns, string(name)) | ||
name = make([]rune, 0) | ||
continue | ||
} | ||
if s[i] == ')' { | ||
state = parseAllColumnsState_State_End | ||
columns = append(columns, string(name)) | ||
} | ||
if isQuote(s[i]) { | ||
return nil, fmt.Errorf("unexpected token: %s", string(s[i])) | ||
} | ||
if isSpace(s[i]) { | ||
state = parseAllColumnsState_EndOfName | ||
columns = append(columns, string(name)) | ||
name = make([]rune, 0) | ||
continue | ||
} | ||
name = append(name, s[i]) | ||
case parseAllColumnsState_ReadingQuotedName: | ||
if s[i] == quote { | ||
// check if quote character is escaped | ||
if i+1 < len(s) && s[i+1] == quote { | ||
name = append(name, quote) | ||
i++ | ||
continue | ||
} | ||
state = parseAllColumnsState_EndOfName | ||
columns = append(columns, string(name)) | ||
name = make([]rune, 0) | ||
continue | ||
} | ||
name = append(name, s[i]) | ||
case parseAllColumnsState_EndOfName: | ||
if isSpace(s[i]) { | ||
continue | ||
} | ||
if isSeparator(s[i]) { | ||
state = parseAllColumnsState_Beginning | ||
continue | ||
} | ||
if s[i] == ')' { | ||
state = parseAllColumnsState_State_End | ||
continue | ||
} | ||
return nil, fmt.Errorf("unexpected token: %s", string(s[i])) | ||
case parseAllColumnsState_State_End: | ||
break | ||
} | ||
} | ||
if state != parseAllColumnsState_State_End { | ||
return nil, errors.New("unexpected end") | ||
} | ||
return columns, nil | ||
} | ||
|
||
func isSpace(r rune) bool { | ||
return r == ' ' || r == '\t' | ||
} | ||
|
||
func isQuote(r rune) bool { | ||
return r == '`' || r == '"' || r == '\'' | ||
} | ||
|
||
func isSeparator(r rune) bool { | ||
return r == ',' | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package gormlite | ||
|
||
import "testing" | ||
|
||
func TestParseAllColumns(t *testing.T) { | ||
tc := []struct { | ||
name string | ||
input string | ||
expected []string | ||
}{ | ||
{ | ||
name: "Simple case", | ||
input: "PRIMARY KEY (column1, column2)", | ||
expected: []string{"column1", "column2"}, | ||
}, | ||
{ | ||
name: "Quoted column name", | ||
input: "PRIMARY KEY (`column,xxx`, \"column 2\", \"column)3\", 'column''4', \"column\"\"5\")", | ||
expected: []string{"column,xxx", "column 2", "column)3", "column'4", "column\"5"}, | ||
}, | ||
{ | ||
name: "Japanese column name", | ||
input: "PRIMARY KEY (カラム1, `カラム2`)", | ||
expected: []string{"カラム1", "カラム2"}, | ||
}, | ||
{ | ||
name: "Column name quoted with []", | ||
input: "PRIMARY KEY ([column1], [column2])", | ||
expected: []string{"column1", "column2"}, | ||
}, | ||
} | ||
for _, tt := range tc { | ||
t.Run(tt.name, func(t *testing.T) { | ||
cols, err := parseAllColumns(tt.input) | ||
if err != nil { | ||
t.Errorf("Failed to parse columns: %s", err) | ||
} | ||
if len(cols) != len(tt.expected) { | ||
t.Errorf("Expected %d columns, got %d", len(tt.expected), len(cols)) | ||
} | ||
for i, col := range cols { | ||
if col != tt.expected[i] { | ||
t.Errorf("Expected %s, got %s", tt.expected[i], col) | ||
} | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters