diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 6136f6e..5d14909 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -34,7 +34,7 @@ jobs: - name: Setup TinyGo uses: acifani/setup-tinygo@v1 with: - tinygo-version: '0.27.0' + tinygo-version: '0.29.0' - name: Version 👍 id: version-bump diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5e80320..141c352 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,7 @@ jobs: test: strategy: matrix: - go-version: [1.18.x, v1.19.x] + go-version: [1.18.x, v1.19.x, v1.20.x] os: [ubuntu-latest] runs-on: ${{ matrix.os }} steps: @@ -70,7 +70,7 @@ jobs: - name: Setup 🐹 uses: acifani/setup-tinygo@v1 with: - tinygo-version: 0.27.0 + tinygo-version: 0.29.0 - name: Install 🔧 run: npm install diff --git a/.gitignore b/.gitignore index 600d2d3..4c965a0 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ -.vscode \ No newline at end of file +.vscode +.DS_Store +diagrams* +s2ts_gen_*.go \ No newline at end of file diff --git a/Makefile b/Makefile index f4a4f10..3ce7877 100644 --- a/Makefile +++ b/Makefile @@ -13,4 +13,23 @@ generate: # requires java generate-diagrams: go run ebnf/main.go grammar.y | java -jar rr/rr.war -suppressebnf -color:#FFFFFF -out:diagrams.xhtml - -.PHONY: generate-diagrams \ No newline at end of file +.PHONY: generate-diagrams + + +# go get -u -v github.com/OneOfOne/struct2ts/... +types: + struct2ts --interface --no-helpers \ + sqlparser.CreateTable \ + sqlparser.ColumnConstraintPrimaryKey \ + sqlparser.ColumnConstraintNotNull \ + sqlparser.ColumnConstraintUnique \ + sqlparser.ColumnConstraintCheck \ + sqlparser.ColumnConstraintDefault \ + sqlparser.ColumnConstraintGenerated \ + sqlparser.TableConstraintPrimaryKey \ + sqlparser.TableConstraintUnique \ + sqlparser.TableConstraintCheck \ + > js/go-types.d.ts + echo "export type ColumnConstraint = ColumnConstraintPrimaryKey | ColumnConstraintNotNull | ColumnConstraintUnique | ColumnConstraintCheck | ColumnConstraintDefault | ColumnConstraintGenerated & { Type: string };" >> js/go-types.d.ts + echo "export type TableConstraint = TableConstraintPrimaryKey | TableConstraintUnique | TableConstraintCheck;" >> js/go-types.d.ts +.PHONY: types \ No newline at end of file diff --git a/ast.go b/ast.go index dd7ebee..3491bd4 100644 --- a/ast.go +++ b/ast.go @@ -3,6 +3,7 @@ package sqlparser import ( "crypto/sha256" "encoding/hex" + "encoding/json" "errors" "fmt" "sort" @@ -1465,6 +1466,46 @@ func (node *CreateTable) StructureHash() string { return hex.EncodeToString(hash) } +// UnmarshalJSON implements the json.Marshaler interface. +func (node *CreateTable) UnmarshalJSON(data []byte) error { + var v struct { + Table *Table + ColumnsDef []*ColumnDef + Constraints []json.RawMessage + StrictMode bool + } + if err := json.Unmarshal(data, &v); err != nil { + return err + } + node.Table = v.Table + node.StrictMode = v.StrictMode + node.ColumnsDef = v.ColumnsDef + for _, constraintData := range v.Constraints { + var constraintType struct { + Type string + } + if err := json.Unmarshal(constraintData, &constraintType); err != nil { + return err + } + + var constraint TableConstraint + switch constraintType.Type { + case "primary-key": + constraint = &TableConstraintPrimaryKey{} + case "unique": + constraint = &TableConstraintUnique{} + default: + return fmt.Errorf("unable to process constraint type: %s", constraintType.Type) + } + + if err := json.Unmarshal(constraintData, constraint); err != nil { + return err + } + node.Constraints = append(node.Constraints, constraint) + } + return nil +} + // ColumnDef represents the column definition of a CREATE TABLE statement. type ColumnDef struct { Column *Column @@ -1514,6 +1555,46 @@ func (node *ColumnDef) HasPrimaryKey() bool { return false } +// UnmarshalJSON implements the json.Marshaler interface. +func (node *ColumnDef) UnmarshalJSON(data []byte) error { + var v struct { + Column *Column + Type string + Constraints []json.RawMessage + } + if err := json.Unmarshal(data, &v); err != nil { + return err + } + node.Type = v.Type + node.Column = v.Column + for _, constraintData := range v.Constraints { + var constraintType struct { + Type string + } + if err := json.Unmarshal(constraintData, &constraintType); err != nil { + return err + } + + var constraint ColumnConstraint + switch constraintType.Type { + case "primary-key": + constraint = &ColumnConstraintPrimaryKey{} + case "not-null": + constraint = &ColumnConstraintNotNull{} + case "unique": + constraint = &ColumnConstraintUnique{} + default: + return fmt.Errorf("unable to process constraint type: %s", constraintType.Type) + } + + if err := json.Unmarshal(constraintData, constraint); err != nil { + return err + } + node.Constraints = append(node.Constraints, constraint) + } + return nil +} + // Types for ColumnDef type. const ( TypeIntStr = "int" @@ -1580,6 +1661,35 @@ const ( PrimaryKeyOrderDesc = "desc" ) +// MarshalJSON implements the json.Marshaler interface. +func (node *ColumnConstraintPrimaryKey) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type string + ColumnConstraintPrimaryKey + }{ + Type: "primary-key", + ColumnConstraintPrimaryKey: ColumnConstraintPrimaryKey{ + Name: node.Name, + Order: node.Order, + AutoIncrement: node.AutoIncrement, + }, + }) +} + +// func (c *ColumnConstraintPrimaryKey) UnmarshalJSON(data []byte) error { +// var v struct { +// Type string +// ColumnConstraintPrimaryKey +// } +// if err := json.Unmarshal(data, &v); err != nil { +// return err +// } +// c.Name = v.Name +// c.Order = v.Order +// c.AutoIncrement = v.AutoIncrement +// return nil +// } + // ColumnConstraintNotNull represents a NOT NULL column constraint for CREATE TABLE. type ColumnConstraintNotNull struct { Name Identifier @@ -1603,6 +1713,31 @@ func (node *ColumnConstraintNotNull) walkSubtree(visit Visit) error { return Walk(visit, node.Name) } +// MarshalJSON implements the json.Marshaler interface. +func (node *ColumnConstraintNotNull) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type string + ColumnConstraintNotNull + }{ + Type: "not-null", + ColumnConstraintNotNull: ColumnConstraintNotNull{ + Name: node.Name, + }, + }) +} + +// func (c *ColumnConstraintNotNull) UnmarshalJSON(data []byte) error { +// var v struct { +// Type string +// ColumnConstraintNotNull +// } +// if err := json.Unmarshal(data, &v); err != nil { +// return err +// } +// c.Name = v.Name +// return nil +// } + // ColumnConstraintUnique represents a UNIQUE column constraint for CREATE TABLE. type ColumnConstraintUnique struct { Name Identifier @@ -1626,6 +1761,31 @@ func (node *ColumnConstraintUnique) walkSubtree(visit Visit) error { return Walk(visit, node.Name) } +// MarshalJSON implements the json.Marshaler interface. +func (node *ColumnConstraintUnique) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type string + ColumnConstraintUnique + }{ + Type: "unique", + ColumnConstraintUnique: ColumnConstraintUnique{ + Name: node.Name, + }, + }) +} + +// func (c *ColumnConstraintUnique) UnmarshalJSON(data []byte) error { +// var v struct { +// Type string +// ColumnConstraintUnique +// } +// if err := json.Unmarshal(data, &v); err != nil { +// return err +// } +// c.Name = v.Name +// return nil +// } + // ColumnConstraintCheck represents a CHECK column constraint for CREATE TABLE. type ColumnConstraintCheck struct { Name Identifier @@ -1649,6 +1809,33 @@ func (node *ColumnConstraintCheck) walkSubtree(visit Visit) error { return Walk(visit, node.Name, node.Expr) } +// MarshalJSON implements the json.Marshaler interface. +func (node *ColumnConstraintCheck) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type string + ColumnConstraintCheck + }{ + Type: "check", + ColumnConstraintCheck: ColumnConstraintCheck{ + Name: node.Name, + Expr: node.Expr, + }, + }) +} + +// func (c *ColumnConstraintCheck) UnmarshalJSON(data []byte) error { +// var v struct { +// Type string +// ColumnConstraintCheck +// } +// if err := json.Unmarshal(data, &v); err != nil { +// return err +// } +// c.Name = v.Name +// c.Expr = v.Expr +// return nil +// } + // ColumnConstraintDefault represents a DEFAULT column constraint for CREATE TABLE. type ColumnConstraintDefault struct { Name Identifier @@ -1676,6 +1863,35 @@ func (node *ColumnConstraintDefault) walkSubtree(visit Visit) error { return Walk(visit, node.Name, node.Expr) } +// MarshalJSON implements the json.Marshaler interface. +func (node *ColumnConstraintDefault) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type string + ColumnConstraintDefault + }{ + Type: "default", + ColumnConstraintDefault: ColumnConstraintDefault{ + Name: node.Name, + Expr: node.Expr, + Parenthesis: node.Parenthesis, + }, + }) +} + +// func (c *ColumnConstraintDefault) UnmarshalJSON(data []byte) error { +// var v struct { +// Type string +// ColumnConstraintDefault +// } +// if err := json.Unmarshal(data, &v); err != nil { +// return err +// } +// c.Name = v.Name +// c.Expr = v.Expr +// c.Parenthesis = v.Parenthesis +// return nil +// } + // ColumnConstraintGenerated represents a GENERATED ALWAYS column constraint for CREATE TABLE. type ColumnConstraintGenerated struct { Name Identifier @@ -1717,6 +1933,37 @@ func (node *ColumnConstraintGenerated) walkSubtree(visit Visit) error { return Walk(visit, node.Name, node.Expr) } +// MarshalJSON implements the json.Marshaler interface. +func (node *ColumnConstraintGenerated) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type string + ColumnConstraintGenerated + }{ + Type: "generated", + ColumnConstraintGenerated: ColumnConstraintGenerated{ + Name: node.Name, + Expr: node.Expr, + GeneratedAlways: node.GeneratedAlways, + IsStored: node.IsStored, + }, + }) +} + +// func (c *ColumnConstraintGenerated) UnmarshalJSON(data []byte) error { +// var v struct { +// Type string +// ColumnConstraintGenerated +// } +// if err := json.Unmarshal(data, &v); err != nil { +// return err +// } +// c.Name = v.Name +// c.Expr = v.Expr +// c.GeneratedAlways = v.GeneratedAlways +// c.IsStored = v.IsStored +// return nil +// } + // TableConstraint is a contrainst applied to the whole table in a CREATE TABLE statement. type TableConstraint interface { iTableConstraint() @@ -1751,6 +1998,20 @@ func (node *TableConstraintPrimaryKey) walkSubtree(visit Visit) error { return Walk(visit, node.Name, node.Columns) } +// MarshalJSON implements the json.Marshaler interface. +func (node *TableConstraintPrimaryKey) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type string + TableConstraintPrimaryKey + }{ + Type: "primary-key", + TableConstraintPrimaryKey: TableConstraintPrimaryKey{ + Name: node.Name, + Columns: node.Columns, + }, + }) +} + // TableConstraintUnique is a UNIQUE constraint for table definition. type TableConstraintUnique struct { Name Identifier @@ -1775,6 +2036,20 @@ func (node *TableConstraintUnique) walkSubtree(visit Visit) error { return Walk(visit, node.Name, node.Columns) } +// MarshalJSON implements the json.Marshaler interface. +func (node *TableConstraintUnique) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type string + TableConstraintUnique + }{ + Type: "unique", + TableConstraintUnique: TableConstraintUnique{ + Name: node.Name, + Columns: node.Columns, + }, + }) +} + // TableConstraintCheck is a CHECK constraint for table definition. type TableConstraintCheck struct { Name Identifier @@ -1799,6 +2074,20 @@ func (node *TableConstraintCheck) walkSubtree(visit Visit) error { return Walk(visit, node.Name, node.Expr) } +// MarshalJSON implements the json.Marshaler interface. +func (node *TableConstraintCheck) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type string + TableConstraintCheck + }{ + Type: "check", + TableConstraintCheck: TableConstraintCheck{ + Name: node.Name, + Expr: node.Expr, + }, + }) +} + // Insert represents an INSERT statement. type Insert struct { Table *Table diff --git a/cmd/wasm/main.go b/cmd/wasm/main.go index f6ed709..a0e20b5 100644 --- a/cmd/wasm/main.go +++ b/cmd/wasm/main.go @@ -2,6 +2,7 @@ package main import ( + "encoding/json" "regexp" "strings" "syscall/js" @@ -30,6 +31,22 @@ type EnclosingType struct { close string } +var ( + Console js.Value + JSON js.Value + Error js.Value + TypeError js.Value + Promise js.Value +) + +func init() { + Console = js.Global().Get("console") + TypeError = js.Global().Get("TypeError") + Error = js.Global().Get("Error") + Promise = js.Global().Get("Promise") + JSON = js.Global().Get("JSON") +} + func getEnclosures() []EnclosingType { return []EnclosingType{ {open: "`", close: "`"}, @@ -65,9 +82,65 @@ func UpdateTableNames(node sqlparser.Node, nameMapper func(string) (string, bool return node, nil } +func createStatementFromObject(this js.Value, args []js.Value) interface{} { + if len(args) < 1 { + return Promise.Call("reject", Error.New("missing required argument: ast")) + } + astObject := args[0] + if astObject.Type() != js.TypeObject { + return Promise.Call("reject", TypeError.New("invalid argument: object expected")) + } + handler := js.FuncOf(func(this js.Value, args []js.Value) interface{} { + resolve := args[0] + reject := args[1] + go func() interface{} { + jsonString := JSON.Call("stringify", astObject).String() + var create sqlparser.CreateTable + if err := json.Unmarshal([]byte(jsonString), &create); err != nil { + return reject.Invoke(Error.New("Error unmarshaling into struct: " + err.Error())) + } + var response interface{} = create.String() + return resolve.Invoke(js.ValueOf(response)) + }() + return nil + }) + return Promise.New(handler) +} + +func createStatementToObject(this js.Value, args []js.Value) interface{} { + if len(args) < 1 { + return Promise.Call("reject", Error.New("missing required argument: statement")) + } + statement := args[0].String() + handler := js.FuncOf(func(this js.Value, args []js.Value) interface{} { + resolve := args[0] + reject := args[1] + go func() interface{} { + ast, err := sqlparser.Parse(statement) + if err != nil { + return reject.Invoke(Error.New("error parsing statement: " + err.Error())) + } + if len(ast.Statements) == 0 { + return reject.Invoke(Error.New("error parsing statement: empty string")) + } + if len(ast.Statements) > 1 { + return reject.Invoke(Error.New("expected single create statement")) + } + create, ok := ast.Statements[0].(sqlparser.CreateTableStatement) + if !ok { + return reject.Invoke(Error.New("expected single create statement")) + } + b, _ := json.Marshal(&create) + var response map[string]interface{} + _ = json.Unmarshal(b, &response) + return resolve.Invoke(js.ValueOf(response)) + }() + return nil + }) + return Promise.New(handler) +} + func validateTableName(this js.Value, args []js.Value) interface{} { - Error := js.Global().Get("Error") - Promise := js.Global().Get("Promise") if len(args) < 1 { return Promise.Call("reject", Error.New("missing required argument: tableName")) } @@ -108,8 +181,6 @@ func validateTableName(this js.Value, args []js.Value) interface{} { } func getUniqueTableNames(this js.Value, args []js.Value) interface{} { - Error := js.Global().Get("Error") - Promise := js.Global().Get("Promise") if len(args) < 1 { return Promise.Call("reject", Error.New("missing required argument: statement")) } @@ -135,8 +206,6 @@ func getUniqueTableNames(this js.Value, args []js.Value) interface{} { } func normalize(this js.Value, args []js.Value) interface{} { - Error := js.Global().Get("Error") - Promise := js.Global().Get("Promise") if len(args) < 1 { return Promise.Call("reject", Error.New("missing required argument: statement")) } @@ -236,9 +305,11 @@ func getEnclosedName(name string) (string, EnclosingType, bool) { func main() { // Outer object is exported globally and contains these keys js.Global().Set(GLOBAL_NAME, js.ValueOf(map[string]interface{}{ - "normalize": js.FuncOf(normalize), - "validateTableName": js.FuncOf(validateTableName), - "getUniqueTableNames": js.FuncOf(getUniqueTableNames), + "normalize": js.FuncOf(normalize), + "validateTableName": js.FuncOf(validateTableName), + "getUniqueTableNames": js.FuncOf(getUniqueTableNames), + "createStatementFromObject": js.FuncOf(createStatementFromObject), + "createStatementToObject": js.FuncOf(createStatementToObject), })) <-make(chan bool) diff --git a/go.mod b/go.mod index 42dcd39..18c67ea 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,12 @@ require ( ) require ( + github.com/OneOfOne/struct2ts v1.0.6 // indirect + github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc // indirect + github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + golang.org/x/tools v0.0.0-20190213135902-6bedcd10978a // indirect + gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index d0a3fe9..93d2f42 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,9 @@ +github.com/OneOfOne/struct2ts v1.0.6 h1:kLFEisG4K43k1thctN9BNZP4Y/RxRbO8tPyi3G5qPl4= +github.com/OneOfOne/struct2ts v1.0.6/go.mod h1:GbIenlFXroS2wRhpYXHEq7y7HWsY3SFBIKxkqzbnAsU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 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= @@ -14,10 +20,15 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN 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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 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= +golang.org/x/tools v0.0.0-20190213135902-6bedcd10978a h1:ncPOGSo3avrTTUKHvDmwoS5E5of95qqNwftSXoxX+Wk= +golang.org/x/tools v0.0.0-20190213135902-6bedcd10978a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 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= diff --git a/helpers_test.go b/helpers_test.go index 0c431dd..1e13f8d 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -1,6 +1,7 @@ package sqlparser import ( + "encoding/json" "fmt" "testing" @@ -155,3 +156,42 @@ func TestWalk(t *testing.T) { require.NoError(t, err) }) } + +func TestJsonMarshalling(t *testing.T) { + t.Parallel() + + t.Run("roundtrip", func(t *testing.T) { + t.Parallel() + + sql := "CREATE TABLE t (id INT CONSTRAINT nm NOT NULL, id2 INT, CONSTRAINT pk PRIMARY KEY (id), CONSTRAINT un UNIQUE (id, id2));" // nolint + ast, err := Parse(sql) + require.NoError(t, err) + create, ok := ast.Statements[0].(CreateTableStatement) + require.True(t, ok) + table, ok := create.(*CreateTable) + require.True(t, ok) + b, err := json.Marshal(&table) + require.NoError(t, err) + var output CreateTable + err = json.Unmarshal(b, &output) + require.NoError(t, err) + require.Equal(t, ast.String(), output.String()) + }) + + t.Run("limited types on unmarshall", func(t *testing.T) { + t.Parallel() + + sql := "CREATE TABLE t (a INT CONSTRAINT default_constraint DEFAULT 0, b INT DEFAULT 1, c INT DEFAULT 0x1, d TEXT DEFAULT 'foo', e TEXT DEFAULT ('foo'), f INT DEFAULT +1);" // nolint + ast, err := Parse(sql) + require.NoError(t, err) + create, ok := ast.Statements[0].(CreateTableStatement) + require.True(t, ok) + table, ok := create.(*CreateTable) + require.True(t, ok) + b, err := json.Marshal(&table) + require.NoError(t, err) + var output CreateTable + err = json.Unmarshal(b, &output) + require.Error(t, err) + }) +} diff --git a/js/.eslintrc.json b/js/.eslintrc.json index 277300f..ea644cf 100644 --- a/js/.eslintrc.json +++ b/js/.eslintrc.json @@ -12,6 +12,7 @@ "ecmaVersion": 12 }, "rules": { - "import/order": "warn" + "import/order": "warn", + "no-use-before-define": "off" } } diff --git a/js/README.md b/js/README.md index 857b4a1..4b77fd2 100644 --- a/js/README.md +++ b/js/README.md @@ -72,6 +72,8 @@ To get started clone this repo. ## Install tinygo +We require tinygo version `0.28.1` or greater + ``` brew tap tinygo-org/tools brew install tinygo @@ -79,10 +81,11 @@ brew install tinygo ## Fetch wasm helpers -Use the corresponding tinygo version +Use the corresponding tinygo version. +**Warning** this will overwrite any existing `wasm_exec.js` file, which has Tableland specific modifications. ``` -wget https://raw.githubusercontent.com/tinygo-org/tinygo/v0.23.0/targets/wasm_exec.js +wget https://raw.githubusercontent.com/tinygo-org/tinygo/v0.29.0/targets/wasm_exec.js ``` ## Build with tinygo @@ -92,10 +95,20 @@ tinygo build -gc=leaking -no-debug -o main.wasm -target wasm ./main.go wasm-opt -O main.wasm -o main.wasm ``` +## Generate types + +From the top-level directory: + +``` +go get github.com/OneOfOne/struct2ts/... +make types +``` + or use the build scripts: ``` npm install +npm run build:go-types npm run build ``` diff --git a/js/go-types.d.ts b/js/go-types.d.ts new file mode 100644 index 0000000..6e73710 --- /dev/null +++ b/js/go-types.d.ts @@ -0,0 +1,103 @@ +// this file was automatically generated, DO NOT EDIT +// structs +// struct2ts:github.com/tablelandnetwork/sqlparser.Table +export interface Table { + Name: string; + IsTarget: boolean; +} + +// struct2ts:github.com/tablelandnetwork/sqlparser.Column +export interface Column { + Name: string; + TableRef: Table | null; +} + +// struct2ts:github.com/tablelandnetwork/sqlparser.ColumnDef +export interface ColumnDef { + Column: Column | null; + Type: string; + Constraints: ColumnConstraint[] | null; +} + +// struct2ts:github.com/tablelandnetwork/sqlparser.CreateTable +export interface CreateTable { + Table: Table | null; + ColumnsDef: ColumnDef[] | null; + Constraints: TableConstraint[] | null; + StrictMode: boolean; +} + +// struct2ts:github.com/tablelandnetwork/sqlparser.ColumnConstraintPrimaryKey +export interface ColumnConstraintPrimaryKey { + Name: string; + Order: string; + AutoIncrement: boolean; +} + +// struct2ts:github.com/tablelandnetwork/sqlparser.ColumnConstraintNotNull +export interface ColumnConstraintNotNull { + Name: string; +} + +// struct2ts:github.com/tablelandnetwork/sqlparser.ColumnConstraintUnique +export interface ColumnConstraintUnique { + Name: string; +} + +// struct2ts:github.com/tablelandnetwork/sqlparser.ColumnConstraintCheck +export interface ColumnConstraintCheck { + Name: string; + Expr: any; +} + +// struct2ts:github.com/tablelandnetwork/sqlparser.ColumnConstraintDefault +export interface ColumnConstraintDefault { + Name: string; + Expr: any; + Parenthesis: boolean; +} + +// struct2ts:github.com/tablelandnetwork/sqlparser.ColumnConstraintGenerated +export interface ColumnConstraintGenerated { + Name: string; + Expr: any; + GeneratedAlways: boolean; + IsStored: boolean; +} + +// struct2ts:github.com/tablelandnetwork/sqlparser.IndexedColumn +export interface IndexedColumn { + Column: Column | null; + CollationName: string; + Order: string; +} + +// struct2ts:github.com/tablelandnetwork/sqlparser.TableConstraintPrimaryKey +export interface TableConstraintPrimaryKey { + Name: string; + Columns: IndexedColumn[] | null; +} + +// struct2ts:github.com/tablelandnetwork/sqlparser.TableConstraintUnique +export interface TableConstraintUnique { + Name: string; + Columns: Column[] | null; +} + +// struct2ts:github.com/tablelandnetwork/sqlparser.TableConstraintCheck +export interface TableConstraintCheck { + Name: string; + Expr: any; +} + +export type ColumnConstraint = + | ColumnConstraintPrimaryKey + | ColumnConstraintNotNull + | ColumnConstraintUnique + | ColumnConstraintCheck + | ColumnConstraintDefault + | (ColumnConstraintGenerated & { Type: string }); +export type TableConstraint = + | TableConstraintPrimaryKey + | TableConstraintUnique + | TableConstraintCheck; diff --git a/js/main.js b/js/main.js index 0ec89d2..5a36d64 100644 --- a/js/main.js +++ b/js/main.js @@ -1,10 +1,11 @@ +// @ts-check +/* global Go */ + // Need to optionally shim `crypto.getRandomValues` and esbuild needs the // import to come before importing `wasm_exec.js` import "./polyfills/crypto.js"; - -// @ts-check -/* global Go */ import "./wasm_exec.js"; +// @ts-ignore import mainWasm from "./main.wasm"; // @ts-ignore diff --git a/js/main.wasm b/js/main.wasm index d8aa0f3..6bfaca7 100755 Binary files a/js/main.wasm and b/js/main.wasm differ diff --git a/js/package.json b/js/package.json index 22b8f44..634d655 100644 --- a/js/package.json +++ b/js/package.json @@ -52,11 +52,12 @@ "wasm:go": "tinygo build -gc=leaking -no-debug -o main.wasm -target wasm ../cmd/wasm/main.go", "wasm:opt": "npx wasm-opt -O main.wasm -o main.wasm", "fixup": "echo '{\n \"type\": \"commonjs\"\n}' > cjs/package.json", + "build:go-types": "cd .. && make types && cd js && npm run prettier -- --write go-types.d.ts", "build:cjs": "node ./cjs-build.js && npm run fixup", "build:esm": "node ./esm-build.js", "build:wasm": "npm run wasm:go && npm run wasm:opt", "build": "npm run build:wasm && npm run build:cjs && npm run build:esm", - "clean": "rm -rf main.wasm cjs", + "clean": "rm -rf main.wasm cjs go-types.d.ts", "prepublishOnly": "npm run build" }, "tsd": { diff --git a/js/test/example.html b/js/test/example.html index c33e28c..e2f769d 100644 --- a/js/test/example.html +++ b/js/test/example.html @@ -1,26 +1,29 @@ -
- - - -
- SELECT * from blah WHERE id = 1;
-
+ SELECT * from blah WHERE id = 1;
+