Skip to content

Commit

Permalink
added index kind
Browse files Browse the repository at this point in the history
  • Loading branch information
adranwit committed Aug 5, 2024
1 parent 3e49110 commit 5b3b5b7
Show file tree
Hide file tree
Showing 9 changed files with 278 additions and 11 deletions.
12 changes: 1 addition & 11 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,22 +1,12 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/viant/parsly v0.3.2-0.20231120160314-11ec855ce00a h1:H+7xS8C8Ywjxc0EfiKL9m+A7AF6JqkJKu5W+7zus/W0=
github.com/viant/parsly v0.3.2-0.20231120160314-11ec855ce00a/go.mod h1:4PKQzioRT9R99ceIhZ6tCD3tp0H0n2dEoIOaLulVvrg=
github.com/viant/parsly v0.3.3-0.20240717150634-e1afaedb691b h1:3q166tV28yFdbFV+tXXjH7ViKAmgAgGdoWzMtvhQv28=
github.com/viant/parsly v0.3.3-0.20240717150634-e1afaedb691b/go.mod h1:85fneXJbErKMGhSQto3A5ElTQCwl3t74U9cSV0waBHw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
150 changes: 150 additions & 0 deletions index.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package sqlparser

import (
"fmt"
"github.com/viant/parsly"
"github.com/viant/sqlparser/index"
"strings"
)

// ParseDropIndex parses drop table
func ParseDropIndex(SQL string) (*index.Drop, error) {
result := &index.Drop{}
SQL = removeSQLComments(SQL)
cursor := parsly.NewCursor("", []byte(SQL), 0)
err := parseDropIndex(cursor, result)
if err != nil {
return result, fmt.Errorf("%s", SQL)
}
return result, err
}

func parseDropIndex(cursor *parsly.Cursor, dest *index.Drop) error {
match := cursor.MatchAfterOptional(whitespaceMatcher, dropIndexMatcher)
if match.Code != dropIndexToken {
return cursor.NewError(createMatcher)
}
if match = cursor.MatchOne(whitespaceMatcher); match.Code != whitespaceCode {
return cursor.NewError(whitespaceMatcher)
}
if match = cursor.MatchOne(ifExistsMatcher); match.Code == ifExistsToken {
dest.IfExists = true
}
match = cursor.MatchAfterOptional(whitespaceMatcher, identifierMatcher)
if match.Code != identifierCode {
return cursor.NewError(ifNotExistsMatcher)
}
dest.Name = match.Text(cursor)
match = cursor.MatchAfterOptional(whitespaceMatcher, onKeywordMatcher)
if match.Code != onKeyword {
return cursor.NewError(ifNotExistsMatcher)
}
match = cursor.MatchAfterOptional(whitespaceMatcher, selectorMatcher)
if match.Code == selectorTokenCode {
selector := match.Text(cursor)
if index := strings.Index(selector, "."); index != -1 {
dest.Schema = selector[0:index]
dest.Table = selector[index+1:]
} else {
dest.Table = selector
}
}
return nil
}

// ParseCreateIndex parses create table
func ParseCreateIndex(SQL string) (*index.Create, error) {
result := &index.Create{}
SQL = removeSQLComments(SQL)
result.Spec.SQL = SQL
cursor := parsly.NewCursor("", []byte(SQL), 0)
err := parseCreateIndex(cursor, result)
if err != nil {
return result, fmt.Errorf("%s", SQL)
}
return result, err
}

func parseCreateIndex(cursor *parsly.Cursor, dest *index.Create) error {
match := cursor.MatchAfterOptional(whitespaceMatcher, createMatcher)
if match.Code != createToken {
return cursor.NewError(createMatcher)
}
if match = cursor.MatchOne(whitespaceMatcher); match.Code != whitespaceCode {
return cursor.NewError(whitespaceMatcher)
}

if match = cursor.MatchOne(ifNotExistsMatcher); match.Code == ifNotExistsToken {
dest.IfDoesExists = true
}

match = cursor.MatchAfterOptional(whitespaceMatcher, indexMatcher)
if match.Code == indexToken {
match = cursor.MatchAfterOptional(whitespaceMatcher, identifierMatcher)
if match.Code != identifierCode {
return cursor.NewError(ifNotExistsMatcher)
}
dest.Spec.Name = match.Text(cursor)

} else {
match = cursor.MatchAfterOptional(whitespaceMatcher, identifierMatcher)
if match.Code != identifierCode {
return cursor.NewError(ifNotExistsMatcher)
}
dest.Spec.Type = match.Text(cursor)
match = cursor.MatchAfterOptional(whitespaceMatcher, indexMatcher)
if match.Code != indexToken {
return cursor.NewError(indexMatcher)
}
match = cursor.MatchAfterOptional(whitespaceMatcher, identifierMatcher)
if match.Code != identifierCode {
return cursor.NewError(ifNotExistsMatcher)
}
dest.Spec.Name = match.Text(cursor)
}

match = cursor.MatchAfterOptional(whitespaceMatcher, onKeywordMatcher)
if match.Code != onKeyword {
return cursor.NewError(parenthesesMatcher)
}

match = cursor.MatchAfterOptional(whitespaceMatcher, selectorMatcher)
if match.Code != selectorTokenCode {
return cursor.NewError(selectorMatcher)

}
selector := match.Text(cursor)
if index := strings.Index(selector, "."); index != -1 {
dest.Spec.Schema = selector[0:index]
dest.Spec.Table = selector[index+1:]
} else {
dest.Spec.Table = selector
}

match = cursor.MatchAfterOptional(whitespaceMatcher, parenthesesMatcher)
if match.Code != parenthesesCode {
return cursor.NewError(parenthesesMatcher)
}
columnSpec := match.Text(cursor)
pos := cursor.Pos
columnCursor := parsly.NewCursor(cursor.Path, []byte(columnSpec[1:len(columnSpec)-1]), pos)

return parseIndexColumnSpec(dest, match, columnCursor)
}

func parseIndexColumnSpec(dest *index.Create, match *parsly.TokenMatch, cursor *parsly.Cursor) error {
for {
col := &index.ColumnSpec{}
dest.Spec.Columns = append(dest.Spec.Columns, col)
match = cursor.MatchAfterOptional(whitespaceMatcher, identifierMatcher)
if match.Code != identifierCode {
return cursor.NewError(ifNotExistsMatcher)
}
col.Name = match.Text(cursor)
match = cursor.MatchAfterOptional(whitespaceMatcher, nextMatcher)
if match.Code != nextCode {
break
}
}
return nil
}
7 changes: 7 additions & 0 deletions index/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package index

// Create represetns a create
type Create struct {
IfDoesExists bool
Spec
}
9 changes: 9 additions & 0 deletions index/drop.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package index

// Drop represents a drop
type Drop struct {
IfExists bool
Name string
Schema string
Table string
}
19 changes: 19 additions & 0 deletions index/spec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package index

type (
//Spec represents index specification
Spec struct {
Name string
Schema string
Table string
SQL string
Type string
Storage string
Columns []*ColumnSpec
}

ColumnSpec struct {
Name string
Type string
}
)
39 changes: 39 additions & 0 deletions index_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package sqlparser

import (
"encoding/json"
"fmt"
"github.com/stretchr/testify/assert"
"testing"
)

func TestParseCreateIndex(t *testing.T) {

{

var testCases = []struct {
description string
SQL string
expect string
}{

{
description: "basc create",
SQL: `CREATE UNIQUE INDEX MyIndex ON schema.table1(COL1, COL2);`,
expect: `CREATE UNIQUE INDEX MyIndex ON schema.table1(COL1, COL2);`,
},
}
for _, testCase := range testCases {
index, err := ParseCreateIndex(testCase.SQL)
if !assert.Nil(t, err) {
fmt.Printf("%v\n", testCase.SQL)
continue
}
actual := Stringify(index)
if !assert.EqualValues(t, testCase.expect, actual) {
data, _ := json.Marshal(index)
fmt.Printf("%s\n", data)
}
}
}
}
5 changes: 5 additions & 0 deletions kind.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ func ParseKind(SQL string) Kind {
switch secondToken[0] {
case 't': //drop table
return KindDropTable

case 'i':
return KindDropIndex
}
Expand Down Expand Up @@ -168,6 +169,10 @@ func ParseKind(SQL string) Kind {
case 'i':
return KindCreateIndex
}
switch thirdToken[0] {
case 'i':
return KindCreateIndex
}
}
return KindUnknown
}
15 changes: 15 additions & 0 deletions lex.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const (
parenthesesCode
nextCode
identifierCode
dotCode
starTokenCode
nullTokenCode
notOperator
Expand Down Expand Up @@ -59,10 +60,13 @@ const (
keyTokenCode
notNullToken
createTableToken
createToken
indexToken
defaultToken
ifNotExistsToken
ifExistsToken
dropTableToken
dropIndexToken
deleteCode
withKeyword
unionKeyword
Expand Down Expand Up @@ -140,6 +144,8 @@ var doubleQuotedStringLiteralMatcher = parsly.NewToken(doubleQuotedStringLiteral
var intLiteralMatcher = parsly.NewToken(intLiteral, `INT`, smatcher.NewIntMatcher())
var numericLiteralMatcher = parsly.NewToken(numericLiteral, `NUMERIC`, matcher.NewNumber())

var dotMatcher = parsly.NewToken(dotCode, ".", matcher.NewByte('.'))

var identifierMatcher = parsly.NewToken(identifierCode, "IDENT", smatcher.NewIdentifier())
var selectorMatcher = parsly.NewToken(selectorTokenCode, "SELECTOR", smatcher.NewSelector(false))
var tableMatcher = parsly.NewToken(tableSelectorTokenCode, "TABLE MATCHER", smatcher.NewSelector(true))
Expand Down Expand Up @@ -169,11 +175,20 @@ var ifExistsMatcher = parsly.NewToken(ifExistsToken, "IF EXISTS", matcher.NewSpa
var createTableMatcher = parsly.NewToken(createTableToken, "CREATE TABLE", matcher.NewSpacedSet([]string{
"create table"}, &option.Case{}))

var createMatcher = parsly.NewToken(createToken, "CREATE", matcher.NewSpacedSet([]string{
"create"}, &option.Case{}))

var indexMatcher = parsly.NewToken(indexToken, "INDEX", matcher.NewSpacedSet([]string{
"index"}, &option.Case{}))

var defaultMatcher = parsly.NewToken(defaultToken, "DEFAULT", matcher.NewKeyword("default", &option.Case{}))

var dropTableMatcher = parsly.NewToken(dropTableToken, "DROP TABLE", matcher.NewSpacedSet([]string{
"drop table"}, &option.Case{}))

var dropIndexMatcher = parsly.NewToken(dropIndexToken, "DROP INDEX", matcher.NewSpacedSet([]string{
"drop index"}, &option.Case{}))

var registerKeywordMatcher = parsly.NewToken(registerKeyword, "REGISTER", matcher.NewKeyword("register", &option.Case{}))

var typeKeywordMatcher = parsly.NewToken(typeKeyword, "TYPE", matcher.NewKeyword("type", &option.Case{}))
Expand Down
33 changes: 33 additions & 0 deletions stringify.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/viant/sqlparser/column"
del "github.com/viant/sqlparser/delete"
"github.com/viant/sqlparser/expr"
"github.com/viant/sqlparser/index"
"github.com/viant/sqlparser/insert"
"github.com/viant/sqlparser/node"
"github.com/viant/sqlparser/query"
Expand Down Expand Up @@ -293,6 +294,38 @@ func stringify(n node.Node, builder *bytes.Buffer) {
}
builder.WriteString(")")

case *index.Create:
builder.WriteString("CREATE ")
if actual.Type != "" {
builder.WriteString(actual.Type)
builder.WriteString(" ")
}

builder.WriteString("INDEX ")

if actual.IfDoesExists {
builder.WriteString("IF NOT EXISTS ")
}
builder.WriteString(actual.Name)
builder.WriteString(" ON ")

if actual.Schema != "" {
builder.WriteString(actual.Schema)
builder.WriteString(".")
builder.WriteString(actual.Table)
} else {
builder.WriteString(actual.Table)
}

builder.WriteString("(")
for i, col := range actual.Columns {
if i > 0 {
builder.WriteString(", ")
}
builder.WriteString(col.Name)
}
builder.WriteString(");")

case *column.Spec:
builder.WriteString(actual.Name)
builder.WriteString(" ")
Expand Down

0 comments on commit 5b3b5b7

Please sign in to comment.