From c4a808bbd44a1de2603bbbd331a46a0e2c7f52a6 Mon Sep 17 00:00:00 2001 From: Songa Ogutu Date: Sat, 7 May 2022 12:35:43 +0300 Subject: [PATCH 1/7] Refactor catalog to self document --- internal/sql/catalog/catalog.go | 247 -------------------------------- internal/sql/catalog/func.go | 41 ++++++ internal/sql/catalog/schema.go | 83 +++++++++++ internal/sql/catalog/table.go | 45 ++++++ internal/sql/catalog/types.go | 76 ++++++++++ 5 files changed, 245 insertions(+), 247 deletions(-) diff --git a/internal/sql/catalog/catalog.go b/internal/sql/catalog/catalog.go index e6095c2405..642dab44fb 100644 --- a/internal/sql/catalog/catalog.go +++ b/internal/sql/catalog/catalog.go @@ -1,22 +1,9 @@ package catalog import ( - "strings" - "github.com/kyleconroy/sqlc/internal/sql/ast" - "github.com/kyleconroy/sqlc/internal/sql/sqlerr" ) -func stringSlice(list *ast.List) []string { - items := []string{} - for _, item := range list.Items { - if n, ok := item.(*ast.String); ok { - items = append(items, n.Str) - } - } - return items -} - type Catalog struct { Comment string DefaultSchema string @@ -29,233 +16,6 @@ type Catalog struct { Extensions map[string]struct{} } -func (c *Catalog) getSchema(name string) (*Schema, error) { - for i := range c.Schemas { - if c.Schemas[i].Name == name { - return c.Schemas[i], nil - } - } - return nil, sqlerr.SchemaNotFound(name) -} - -func (c *Catalog) getFunc(rel *ast.FuncName, tns []*ast.TypeName) (*Function, int, error) { - ns := rel.Schema - if ns == "" { - ns = c.DefaultSchema - } - s, err := c.getSchema(ns) - if err != nil { - return nil, -1, err - } - return s.getFunc(rel, tns) -} - -func (c *Catalog) getTable(name *ast.TableName) (*Schema, *Table, error) { - ns := name.Schema - if ns == "" { - ns = c.DefaultSchema - } - var s *Schema - for i := range c.Schemas { - if c.Schemas[i].Name == ns { - s = c.Schemas[i] - break - } - } - if s == nil { - return nil, nil, sqlerr.SchemaNotFound(ns) - } - t, _, err := s.getTable(name) - if err != nil { - return nil, nil, err - } - return s, t, nil -} - -func (c *Catalog) getType(rel *ast.TypeName) (Type, int, error) { - ns := rel.Schema - if ns == "" { - ns = c.DefaultSchema - } - s, err := c.getSchema(ns) - if err != nil { - return nil, -1, err - } - return s.getType(rel) -} - -type Schema struct { - Name string - Tables []*Table - Types []Type - Funcs []*Function - - Comment string -} - -func sameType(a, b *ast.TypeName) bool { - if a.Catalog != b.Catalog { - return false - } - // The pg_catalog schema is searched by default, so take that into - // account when comparing schemas - aSchema := a.Schema - bSchema := b.Schema - if aSchema == "pg_catalog" { - aSchema = "" - } - if bSchema == "pg_catalog" { - bSchema = "" - } - if aSchema != bSchema { - return false - } - if a.Name != b.Name { - return false - } - return true -} - -func (s *Schema) getFunc(rel *ast.FuncName, tns []*ast.TypeName) (*Function, int, error) { - for i := range s.Funcs { - if strings.ToLower(s.Funcs[i].Name) != strings.ToLower(rel.Name) { - continue - } - - args := s.Funcs[i].InArgs() - if len(args) != len(tns) { - continue - } - found := true - for j := range args { - if !sameType(s.Funcs[i].Args[j].Type, tns[j]) { - found = false - break - } - } - if !found { - continue - } - return s.Funcs[i], i, nil - } - return nil, -1, sqlerr.RelationNotFound(rel.Name) -} - -func (s *Schema) getFuncByName(rel *ast.FuncName) (*Function, int, error) { - idx := -1 - name := strings.ToLower(rel.Name) - for i := range s.Funcs { - lowered := strings.ToLower(s.Funcs[i].Name) - if lowered == name && idx >= 0 { - return nil, -1, sqlerr.FunctionNotUnique(rel.Name) - } - if lowered == name { - idx = i - } - } - if idx < 0 { - return nil, -1, sqlerr.RelationNotFound(rel.Name) - } - return s.Funcs[idx], idx, nil -} - -func (s *Schema) getTable(rel *ast.TableName) (*Table, int, error) { - for i := range s.Tables { - if s.Tables[i].Rel.Name == rel.Name { - return s.Tables[i], i, nil - } - } - return nil, -1, sqlerr.RelationNotFound(rel.Name) -} - -func (s *Schema) getType(rel *ast.TypeName) (Type, int, error) { - for i := range s.Types { - switch typ := s.Types[i].(type) { - case *Enum: - if typ.Name == rel.Name { - return s.Types[i], i, nil - } - } - } - return nil, -1, sqlerr.TypeNotFound(rel.Name) -} - -type Table struct { - Rel *ast.TableName - Columns []*Column - Comment string -} - -// TODO: Should this just be ast Nodes? -type Column struct { - Name string - Type ast.TypeName - IsNotNull bool - IsArray bool - Comment string - Length *int -} - -type Type interface { - isType() - - SetComment(string) -} - -type Enum struct { - Name string - Vals []string - Comment string -} - -func (e *Enum) SetComment(c string) { - e.Comment = c -} - -func (e *Enum) isType() { -} - -type CompositeType struct { - Name string - Comment string -} - -func (ct *CompositeType) isType() { -} - -func (ct *CompositeType) SetComment(c string) { - ct.Comment = c -} - -type Function struct { - Name string - Args []*Argument - ReturnType *ast.TypeName - Comment string - Desc string - ReturnTypeNullable bool -} - -func (f *Function) InArgs() []*Argument { - var args []*Argument - for _, a := range f.Args { - switch a.Mode { - case ast.FuncParamTable, ast.FuncParamOut: - continue - default: - args = append(args, a) - } - } - return args -} - -type Argument struct { - Name string - Type *ast.TypeName - HasDefault bool - Mode ast.FuncParamMode -} - func New(def string) *Catalog { return &Catalog{ DefaultSchema: def, @@ -275,13 +35,6 @@ func (c *Catalog) Build(stmts []ast.Statement) error { return nil } -// An interface is used to resolve a circular import between the catalog and compiler packages. -// The createView function requires access to functions in the compiler package to parse the SELECT -// statement that defines the view. -type columnGenerator interface { - OutputColumns(node ast.Node) ([]*Column, error) -} - func (c *Catalog) Update(stmt ast.Statement, colGen columnGenerator) error { if stmt.Raw == nil { return nil diff --git a/internal/sql/catalog/func.go b/internal/sql/catalog/func.go index 760144c135..dacc8c9955 100644 --- a/internal/sql/catalog/func.go +++ b/internal/sql/catalog/func.go @@ -7,6 +7,47 @@ import ( "github.com/kyleconroy/sqlc/internal/sql/sqlerr" ) +type Function struct { + Name string + Args []*Argument + ReturnType *ast.TypeName + Comment string + Desc string + ReturnTypeNullable bool +} + +type Argument struct { + Name string + Type *ast.TypeName + HasDefault bool + Mode ast.FuncParamMode +} + +func (f *Function) InArgs() []*Argument { + var args []*Argument + for _, a := range f.Args { + switch a.Mode { + case ast.FuncParamTable, ast.FuncParamOut: + continue + default: + args = append(args, a) + } + } + return args +} + +func (c *Catalog) getFunc(rel *ast.FuncName, tns []*ast.TypeName) (*Function, int, error) { + ns := rel.Schema + if ns == "" { + ns = c.DefaultSchema + } + s, err := c.getSchema(ns) + if err != nil { + return nil, -1, err + } + return s.getFunc(rel, tns) +} + func (c *Catalog) createFunction(stmt *ast.CreateFunctionStmt) error { ns := stmt.Func.Schema if ns == "" { diff --git a/internal/sql/catalog/schema.go b/internal/sql/catalog/schema.go index a0189c6c05..4cb11b961e 100644 --- a/internal/sql/catalog/schema.go +++ b/internal/sql/catalog/schema.go @@ -2,11 +2,94 @@ package catalog import ( "fmt" + "strings" "github.com/kyleconroy/sqlc/internal/sql/ast" "github.com/kyleconroy/sqlc/internal/sql/sqlerr" ) +type Schema struct { + Name string + Tables []*Table + Types []Type + Funcs []*Function + + Comment string +} + +func (s *Schema) getFunc(rel *ast.FuncName, tns []*ast.TypeName) (*Function, int, error) { + for i := range s.Funcs { + if strings.ToLower(s.Funcs[i].Name) != strings.ToLower(rel.Name) { + continue + } + + args := s.Funcs[i].InArgs() + if len(args) != len(tns) { + continue + } + found := true + for j := range args { + if !sameType(s.Funcs[i].Args[j].Type, tns[j]) { + found = false + break + } + } + if !found { + continue + } + return s.Funcs[i], i, nil + } + return nil, -1, sqlerr.RelationNotFound(rel.Name) +} + +func (s *Schema) getFuncByName(rel *ast.FuncName) (*Function, int, error) { + idx := -1 + name := strings.ToLower(rel.Name) + for i := range s.Funcs { + lowered := strings.ToLower(s.Funcs[i].Name) + if lowered == name && idx >= 0 { + return nil, -1, sqlerr.FunctionNotUnique(rel.Name) + } + if lowered == name { + idx = i + } + } + if idx < 0 { + return nil, -1, sqlerr.RelationNotFound(rel.Name) + } + return s.Funcs[idx], idx, nil +} + +func (s *Schema) getTable(rel *ast.TableName) (*Table, int, error) { + for i := range s.Tables { + if s.Tables[i].Rel.Name == rel.Name { + return s.Tables[i], i, nil + } + } + return nil, -1, sqlerr.RelationNotFound(rel.Name) +} + +func (s *Schema) getType(rel *ast.TypeName) (Type, int, error) { + for i := range s.Types { + switch typ := s.Types[i].(type) { + case *Enum: + if typ.Name == rel.Name { + return s.Types[i], i, nil + } + } + } + return nil, -1, sqlerr.TypeNotFound(rel.Name) +} + +func (c *Catalog) getSchema(name string) (*Schema, error) { + for i := range c.Schemas { + if c.Schemas[i].Name == name { + return c.Schemas[i], nil + } + } + return nil, sqlerr.SchemaNotFound(name) +} + func (c *Catalog) createSchema(stmt *ast.CreateSchemaStmt) error { if stmt.Name == nil { return fmt.Errorf("create schema: empty name") diff --git a/internal/sql/catalog/table.go b/internal/sql/catalog/table.go index 70c99d0111..2029a8bc13 100644 --- a/internal/sql/catalog/table.go +++ b/internal/sql/catalog/table.go @@ -8,6 +8,51 @@ import ( "github.com/kyleconroy/sqlc/internal/sql/sqlerr" ) +type Table struct { + Rel *ast.TableName + Columns []*Column + Comment string +} + +// TODO: Should this just be ast Nodes? +type Column struct { + Name string + Type ast.TypeName + IsNotNull bool + IsArray bool + Comment string + Length *int +} + +// An interface is used to resolve a circular import between the catalog and compiler packages. +// The createView function requires access to functions in the compiler package to parse the SELECT +// statement that defines the view. +type columnGenerator interface { + OutputColumns(node ast.Node) ([]*Column, error) +} + +func (c *Catalog) getTable(name *ast.TableName) (*Schema, *Table, error) { + ns := name.Schema + if ns == "" { + ns = c.DefaultSchema + } + var s *Schema + for i := range c.Schemas { + if c.Schemas[i].Name == ns { + s = c.Schemas[i] + break + } + } + if s == nil { + return nil, nil, sqlerr.SchemaNotFound(ns) + } + t, _, err := s.getTable(name) + if err != nil { + return nil, nil, err + } + return s, t, nil +} + func (c *Catalog) alterTable(stmt *ast.AlterTableStmt) error { var implemented bool for _, item := range stmt.Cmds.Items { diff --git a/internal/sql/catalog/types.go b/internal/sql/catalog/types.go index 7156466a75..74f6389f58 100644 --- a/internal/sql/catalog/types.go +++ b/internal/sql/catalog/types.go @@ -8,6 +8,60 @@ import ( "github.com/kyleconroy/sqlc/internal/sql/sqlerr" ) +type Type interface { + isType() + + SetComment(string) +} + +type Enum struct { + Name string + Vals []string + Comment string +} + +func (e *Enum) SetComment(c string) { + e.Comment = c +} + +func (e *Enum) isType() { +} + +type CompositeType struct { + Name string + Comment string +} + +func (ct *CompositeType) isType() { +} + +func (ct *CompositeType) SetComment(c string) { + ct.Comment = c +} + +func sameType(a, b *ast.TypeName) bool { + if a.Catalog != b.Catalog { + return false + } + // The pg_catalog schema is searched by default, so take that into + // account when comparing schemas + aSchema := a.Schema + bSchema := b.Schema + if aSchema == "pg_catalog" { + aSchema = "" + } + if bSchema == "pg_catalog" { + bSchema = "" + } + if aSchema != bSchema { + return false + } + if a.Name != b.Name { + return false + } + return true +} + func (c *Catalog) createEnum(stmt *ast.CreateEnumStmt) error { ns := stmt.TypeName.Schema if ns == "" { @@ -37,6 +91,28 @@ func (c *Catalog) createEnum(stmt *ast.CreateEnumStmt) error { return nil } +func stringSlice(list *ast.List) []string { + items := []string{} + for _, item := range list.Items { + if n, ok := item.(*ast.String); ok { + items = append(items, n.Str) + } + } + return items +} + +func (c *Catalog) getType(rel *ast.TypeName) (Type, int, error) { + ns := rel.Schema + if ns == "" { + ns = c.DefaultSchema + } + s, err := c.getSchema(ns) + if err != nil { + return nil, -1, err + } + return s.getType(rel) +} + func (c *Catalog) createCompositeType(stmt *ast.CompositeTypeStmt) error { ns := stmt.TypeName.Schema if ns == "" { From 8fc27ce0d78dafb6bdf1bc0c58d76adedbe9a484 Mon Sep 17 00:00:00 2001 From: Songa Ogutu Date: Sun, 8 May 2022 18:32:22 +0300 Subject: [PATCH 2/7] Add comments and tests to pkg catalog --- internal/sql/catalog/catalog.go | 10 +- internal/sql/catalog/catalog_test.go | 30 ++ internal/sql/catalog/func.go | 3 + internal/sql/catalog/func_test.go | 1 + internal/sql/catalog/schema.go | 1 + internal/sql/catalog/schema_test.go | 758 +++++++++++++++++++++++++++ internal/sql/catalog/table.go | 4 + internal/sql/catalog/table_test.go | 40 ++ 8 files changed, 843 insertions(+), 4 deletions(-) create mode 100644 internal/sql/catalog/catalog_test.go create mode 100644 internal/sql/catalog/func_test.go create mode 100644 internal/sql/catalog/schema_test.go create mode 100644 internal/sql/catalog/table_test.go diff --git a/internal/sql/catalog/catalog.go b/internal/sql/catalog/catalog.go index 642dab44fb..699865c74a 100644 --- a/internal/sql/catalog/catalog.go +++ b/internal/sql/catalog/catalog.go @@ -4,6 +4,7 @@ import ( "github.com/kyleconroy/sqlc/internal/sql/ast" ) +// Catalog describes a database instance consisting of metadata in which database objects are defined type Catalog struct { Comment string DefaultSchema string @@ -16,13 +17,14 @@ type Catalog struct { Extensions map[string]struct{} } -func New(def string) *Catalog { +// New creates a new catalog +func New(defaultSchema string) *Catalog { return &Catalog{ - DefaultSchema: def, + DefaultSchema: defaultSchema, Schemas: []*Schema{ - {Name: def}, + {Name: defaultSchema}, }, - Extensions: map[string]struct{}{}, + Extensions: make(map[string]struct{}), } } diff --git a/internal/sql/catalog/catalog_test.go b/internal/sql/catalog/catalog_test.go new file mode 100644 index 0000000000..3595d7cb63 --- /dev/null +++ b/internal/sql/catalog/catalog_test.go @@ -0,0 +1,30 @@ +package catalog + +import "testing" + +func TestNew(t *testing.T) { + + const defaultSchema = "default" + + newCatalog := New(defaultSchema) + + if newCatalog.DefaultSchema == "" { + t.Errorf("newCatalog.DefaultSchema: want %s, got %s", defaultSchema, newCatalog.DefaultSchema) + } + + if newCatalog.Schemas == nil { + t.Error("newCatalog.Schemas should not be nil") + } + + if len(newCatalog.Schemas) != 1 { + t.Errorf("newCatalog.Schemas length want 1, got %d", len(newCatalog.Schemas)) + } + + if newCatalog.Schemas[0].Name != defaultSchema { + t.Error("newCatalog.Schemas should have the default schema") + } + + if newCatalog.Extensions == nil { + t.Error("newCatalog.Extensions should be empty") + } +} diff --git a/internal/sql/catalog/func.go b/internal/sql/catalog/func.go index dacc8c9955..d2891b773c 100644 --- a/internal/sql/catalog/func.go +++ b/internal/sql/catalog/func.go @@ -7,6 +7,9 @@ import ( "github.com/kyleconroy/sqlc/internal/sql/sqlerr" ) +// Function describes a database function +// +// A database function is a method written to performs specific operation on data within the database. type Function struct { Name string Args []*Argument diff --git a/internal/sql/catalog/func_test.go b/internal/sql/catalog/func_test.go new file mode 100644 index 0000000000..e571e24c61 --- /dev/null +++ b/internal/sql/catalog/func_test.go @@ -0,0 +1 @@ +package catalog diff --git a/internal/sql/catalog/schema.go b/internal/sql/catalog/schema.go index 4cb11b961e..3cdfeb5bb8 100644 --- a/internal/sql/catalog/schema.go +++ b/internal/sql/catalog/schema.go @@ -8,6 +8,7 @@ import ( "github.com/kyleconroy/sqlc/internal/sql/sqlerr" ) +// Schema describes how the data in a relational database may relate to other tables or other data models type Schema struct { Name string Tables []*Table diff --git a/internal/sql/catalog/schema_test.go b/internal/sql/catalog/schema_test.go new file mode 100644 index 0000000000..be76e6adf3 --- /dev/null +++ b/internal/sql/catalog/schema_test.go @@ -0,0 +1,758 @@ +package catalog + +import ( + "strings" + "testing" + + "github.com/kyleconroy/sqlc/internal/sql/ast" +) + +func TestSchemaGetFunc(t *testing.T) { + + testCases := []struct { + name string + rel *ast.FuncName + tns []*ast.TypeName + outStub func(t *testing.T, schema *Schema, schemaFunc *Function, funcIndex int, err error) + }{ + { + name: "FunctionFound", + rel: &ast.FuncName{ + Name: "func1", + Schema: "schema1", + }, + tns: []*ast.TypeName{ + { + Name: "type1", + Catalog: "catalog1", + Schema: "schema1", + }, + }, + outStub: func(t *testing.T, schema *Schema, schemaFunc *Function, funcIndex int, err error) { + + if funcIndex < 0 { + t.Errorf("invalid funcIndex want greater than 0 got: %d", funcIndex) + } + + if schema.Funcs[funcIndex].Name != schemaFunc.Name { + t.Errorf("schema function want: %s, got %s", schema.Funcs[funcIndex].Name, schemaFunc.Name) + } + + if err != nil { + t.Errorf("err should be nil got %v", err) + } + }, + }, + { + name: "FunctionAgumentMismatch", + rel: &ast.FuncName{ + Name: "func1", + Schema: "schema1", + }, + tns: []*ast.TypeName{ + { + Name: "type1", + Catalog: "catalog1", + Schema: "schema1", + }, + { + Name: "type2", + Catalog: "catalog1", + Schema: "schema1", + }, + }, + outStub: func(t *testing.T, schema *Schema, schemaFunc *Function, funcIndex int, err error) { + + if funcIndex > -1 { + t.Errorf("invalid funcIndex want less than 0 got: %d", funcIndex) + } + + if schemaFunc != nil { + t.Error("schema function should be nil") + } + + if err == nil { + t.Error("err should not be nil") + } + }, + }, + { + name: "FunctionNameMismatch", + rel: &ast.FuncName{ + Name: "func", + Schema: "schema1", + }, + tns: []*ast.TypeName{ + { + Name: "type1", + Catalog: "catalog1", + Schema: "schema1", + }, + }, + outStub: func(t *testing.T, schema *Schema, schemaFunc *Function, funcIndex int, err error) { + + if funcIndex > -1 { + t.Errorf("invalid funcIndex want less than 0 got: %d", funcIndex) + } + + if schemaFunc != nil { + t.Error("schema function should be nil") + } + + if err == nil { + t.Error("err should not be nil") + } + }, + }, + { + name: "SchemaNameMismatch", + rel: &ast.FuncName{ + Name: "func1", + Schema: "schema2", + }, + tns: []*ast.TypeName{ + { + Name: "type1", + Catalog: "catalog1", + Schema: "schema2", + }, + }, + outStub: func(t *testing.T, schema *Schema, schemaFunc *Function, funcIndex int, err error) { + + if funcIndex > -1 { + t.Errorf("invalid funcIndex want less than 0 got: %d", funcIndex) + } + + if schemaFunc != nil { + t.Error("schema function should be nil") + } + + if err == nil { + t.Error("err should not be nil") + } + }, + }, + } + + schema := &Schema{ + Name: "schema1", + Funcs: []*Function{ + { + Name: "func1", + Args: []*Argument{ + { + Name: "arg1", + Type: &ast.TypeName{ + Name: "type1", + Catalog: "catalog1", + Schema: "schema1", + }, + Mode: ast.FuncParamIn, + }, + }, + }, + { + Name: "func2", + Args: []*Argument{ + { + Name: "arg1", + Type: &ast.TypeName{ + Name: "type1", + Catalog: "catalog1", + Schema: "schema1", + }, + Mode: ast.FuncParamIn, + }, + }, + }, + }, + } + + for i := range testCases { + + tc := testCases[i] + + t.Run(tc.name, func(t *testing.T) { + outFunc, outIndex, err := schema.getFunc(tc.rel, tc.tns) + tc.outStub(t, schema, outFunc, outIndex, err) + }) + } +} + +func TestSchemaGetFuncByName(t *testing.T) { + + schema := &Schema{ + Name: "schema1", + Funcs: []*Function{ + { + Name: "func1", + Args: []*Argument{ + { + Name: "arg1", + Type: &ast.TypeName{ + Name: "type1", + Catalog: "catalog1", + Schema: "schema1", + }, + Mode: ast.FuncParamIn, + }, + }, + }, + { + Name: "func2", + Args: []*Argument{ + { + Name: "arg1", + Type: &ast.TypeName{ + Name: "type1", + Catalog: "catalog1", + Schema: "schema1", + }, + Mode: ast.FuncParamIn, + }, + }, + }, + }, + } + + testCases := []struct { + name string + schema *Schema + rel *ast.FuncName + outStub func(t *testing.T, schema *Schema, schemaFunc *Function, funcIndex int, err error) + }{ + { + name: "FunctionFound", + schema: schema, + rel: &ast.FuncName{ + Name: "func1", + Schema: "schema1", + }, + outStub: func(t *testing.T, schema *Schema, schemaFunc *Function, funcIndex int, err error) { + + if funcIndex < 0 { + t.Errorf("invalid funcIndex want greater than 0 got: %d", funcIndex) + } + + if schema.Funcs[funcIndex].Name != schemaFunc.Name { + t.Errorf("schema function want: %s, got %s", schema.Funcs[funcIndex].Name, schemaFunc.Name) + } + + if err != nil { + t.Errorf("err should be nil got %v", err) + } + }, + }, + { + name: "FunctionNotUnique", + schema: func() *Schema { + + // Create a new schema + + newSchema := Schema{} + newSchema = *schema + + // Add a duplicate func for test + newSchema.Funcs = append(newSchema.Funcs, &Function{ + Name: "func1", + Args: []*Argument{ + { + Name: "arg1", + Type: &ast.TypeName{ + Name: "type1", + Catalog: "catalog1", + Schema: "schema1", + }, + Mode: ast.FuncParamIn, + }, + }, + }) + + return &newSchema + }(), + rel: &ast.FuncName{ + Name: "func1", + Schema: "schema1", + }, + outStub: func(t *testing.T, schema *Schema, schemaFunc *Function, funcIndex int, err error) { + + if funcIndex > -1 { + t.Errorf("invalid funcIndex want less than 0 got: %d", funcIndex) + } + + if schemaFunc != nil { + t.Error("schema function should be nil") + } + + if err == nil { + t.Error("err should not be nil") + } + }, + }, + { + name: "FunctionNotFound", + schema: schema, + rel: &ast.FuncName{ + Name: "func", + Schema: "schema1", + }, + outStub: func(t *testing.T, schema *Schema, schemaFunc *Function, funcIndex int, err error) { + + if funcIndex > -1 { + t.Errorf("invalid funcIndex want less than 0 got: %d", funcIndex) + } + + if schemaFunc != nil { + t.Error("schema function should be nil") + } + + if err == nil { + t.Error("err should not be nil") + } + }, + }, + } + + for i := range testCases { + + tc := testCases[i] + + t.Run(tc.name, func(t *testing.T) { + outFunc, outIndex, err := tc.schema.getFuncByName(tc.rel) + tc.outStub(t, tc.schema, outFunc, outIndex, err) + }) + } +} + +func TestSchemaGetTable(t *testing.T) { + + schema := &Schema{ + Name: "schema1", + Tables: []*Table{ + { + Rel: &ast.TableName{ + Name: "table1", + }, + }, + { + Rel: &ast.TableName{ + Name: "table2", + }, + }, + }, + } + + testCases := []struct { + name string + rel *ast.TableName + outStub func(t *testing.T, schema *Schema, schemaFunc *Table, tableIndex int, err error) + }{ + { + name: "TableFound", + rel: &ast.TableName{ + Name: "table2", + }, + outStub: func(t *testing.T, schema *Schema, schemaTable *Table, tableIndex int, err error) { + + if tableIndex < 0 { + t.Errorf("invalid tableIndex want greater than 0 got: %d", tableIndex) + } + + if schema.Tables[tableIndex].Rel.Name != schemaTable.Rel.Name { + t.Errorf("schema table want: %s, got %s", schema.Tables[tableIndex].Rel.Name, schemaTable.Rel.Name) + } + + if err != nil { + t.Errorf("err should be nil got %v", err) + } + }, + }, + { + name: "TableNotFound", + rel: &ast.TableName{ + Name: "table", + }, + outStub: func(t *testing.T, schema *Schema, schemaTable *Table, tableIndex int, err error) { + + if tableIndex > -1 { + t.Errorf("invalid tableIndex want less than 0 got: %d", tableIndex) + } + + if schemaTable != nil { + t.Error("schema table should be nil") + } + + if err == nil { + t.Error("err should not be nil") + } + }, + }, + } + + for i := range testCases { + + tc := testCases[i] + + t.Run(tc.name, func(t *testing.T) { + outTable, outIndex, err := schema.getTable(tc.rel) + tc.outStub(t, schema, outTable, outIndex, err) + }) + } +} + +func TestSchemaGetType(t *testing.T) { + + schema := &Schema{ + Name: "schema1", + Types: []Type{ + &Enum{ + Name: "emum1", + }, + &Enum{ + Name: "emum2", + }, + &CompositeType{ + Name: "compositeType1", + }, + }, + } + + testCases := []struct { + name string + rel *ast.TypeName + outStub func(t *testing.T, schema *Schema, schemaEnum Type, typeIndex int, err error) + }{ + { + name: "TypeFound", + rel: &ast.TypeName{ + Name: "emum1", + }, + outStub: func(t *testing.T, schema *Schema, schemaType Type, typeIndex int, err error) { + + if typeIndex < 0 { + t.Errorf("invalid typeIndex want greater than 0 got: %d", typeIndex) + } + + if schemaType == nil { + t.Error("schema type should not be nil") + } + + if err != nil { + t.Errorf("err should be nil got %v", err) + } + }, + }, + { + name: "TypeNotFound", + rel: &ast.TypeName{ + Name: "enum", + }, + outStub: func(t *testing.T, schema *Schema, schemaType Type, typeIndex int, err error) { + + if typeIndex > -1 { + t.Errorf("invalid typeIndex want greater than 0 got: %d", typeIndex) + } + + if schemaType != nil { + t.Error("schema type should not be nil") + } + + if err == nil { + t.Error("err should not be nil") + } + }, + }, + { + name: "TypeInvalid", + rel: &ast.TypeName{ + Name: "compositeType1", + }, + outStub: func(t *testing.T, schema *Schema, schemaType Type, typeIndex int, err error) { + + if typeIndex > -1 { + t.Errorf("invalid typeIndex want greater than 0 got: %d", typeIndex) + } + + if schemaType != nil { + t.Error("schema type should not be nil") + } + + if err == nil { + t.Error("err should not be nil") + } + }, + }, + } + + for i := range testCases { + + tc := testCases[i] + + t.Run(tc.name, func(t *testing.T) { + outType, outIndex, err := schema.getType(tc.rel) + tc.outStub(t, schema, outType, outIndex, err) + }) + } +} + +func TestGetSchema(t *testing.T) { + + testCases := []struct { + name string + schemaName string + outStub func(t *testing.T, outSchema *Schema, err error) + }{ + { + name: "Schema Found", + schemaName: "default", + outStub: func(t *testing.T, schema *Schema, err error) { + + if schema.Name != "default" { + t.Errorf("schema name want default got %s", schema.Name) + } + + if err != nil { + t.Errorf("err should be nil got %v", err) + } + }, + }, + { + name: "Schema Not Found", + schemaName: "wrongSchema", + outStub: func(t *testing.T, schema *Schema, err error) { + + if schema != nil { + t.Error("should be nil") + } + + if err == nil { + t.Error("err should not be nil") + } + }, + }, + } + + newCatalog := New("default") + + for i := range testCases { + + tc := testCases[i] + + t.Run(tc.name, func(t *testing.T) { + outSchema, err := newCatalog.getSchema(tc.schemaName) + tc.outStub(t, outSchema, err) + }) + } +} + +func TestCreteSchema(t *testing.T) { + + testCases := []struct { + name string + stmt *ast.CreateSchemaStmt + outStub func(t *testing.T, newCatalog *Catalog, err error) + }{ + { + name: "No Schema Name", + stmt: func() *ast.CreateSchemaStmt { + return &ast.CreateSchemaStmt{ + Name: nil, + } + }(), + outStub: func(t *testing.T, newCatalog *Catalog, err error) { + + if !strings.Contains(err.Error(), "empty name") { + t.Errorf("should contain phrase: empty name, got: %s", err.Error()) + } + + if len(newCatalog.Schemas) != 1 { + t.Errorf("catalog schema length: want 1, got: %d", len(newCatalog.Schemas)) + } + }, + }, + { + name: "Schema Name Exists", + stmt: func() *ast.CreateSchemaStmt { + + schemaName := "default" + + return &ast.CreateSchemaStmt{ + Name: &schemaName, + } + }(), + outStub: func(t *testing.T, newCatalog *Catalog, err error) { + + if err == nil { + t.Error("should not be nil") + } + + if len(newCatalog.Schemas) != 1 { + t.Errorf("catalog schema length: want 1, got: %d", len(newCatalog.Schemas)) + } + }, + }, + { + name: "Schema Created", + stmt: func() *ast.CreateSchemaStmt { + + schemaName := "new_schema" + + return &ast.CreateSchemaStmt{ + Name: &schemaName, + } + }(), + outStub: func(t *testing.T, newCatalog *Catalog, err error) { + + if err != nil { + t.Errorf("should be nil got: %v", err) + } + + if len(newCatalog.Schemas) != 2 { + t.Errorf("catalog schema length: want 2, got: %d", len(newCatalog.Schemas)) + } + }, + }, + } + + newCatalog := New("default") + + for i := range testCases { + + tc := testCases[i] + + t.Run(tc.name, func(t *testing.T) { + err := newCatalog.createSchema(tc.stmt) + tc.outStub(t, newCatalog, err) + }) + } +} + +func TestDropSchema(t *testing.T) { + + testCases := []struct { + name string + stmt *ast.DropSchemaStmt + outStub func(t *testing.T, newCatalog *Catalog, err error) + }{ + { + name: "NoSchemaProvided", + stmt: &ast.DropSchemaStmt{ + Schemas: nil, + }, + outStub: func(t *testing.T, newCatalog *Catalog, err error) { + + if err != nil { + t.Errorf("err should be nil, got: %v", err) + } + + if len(newCatalog.Schemas) != 5 { + t.Errorf("catalog schema length: want 5, got: %d", len(newCatalog.Schemas)) + } + }, + }, + { + name: "DeleteOneSchema", + stmt: &ast.DropSchemaStmt{ + Schemas: []*ast.String{ + { + Str: "schema1", + }, + }, + }, + outStub: func(t *testing.T, newCatalog *Catalog, err error) { + + if err != nil { + t.Errorf("err should be nil, got: %v", err) + } + + if len(newCatalog.Schemas) != 4 { + t.Errorf("catalog schema length: want 4, got: %d", len(newCatalog.Schemas)) + } + }, + }, + { + name: "DeleteMultipleSchema", + stmt: &ast.DropSchemaStmt{ + Schemas: []*ast.String{ + { + Str: "schema1", + }, + { + Str: "schema3", + }, + }, + }, + outStub: func(t *testing.T, newCatalog *Catalog, err error) { + + if err != nil { + t.Errorf("err should be nil, got: %v", err) + } + + if len(newCatalog.Schemas) != 3 { + t.Errorf("catalog schema length: want 3, got: %d", len(newCatalog.Schemas)) + } + }, + }, + { + name: "AllowedMissingSchema", + stmt: &ast.DropSchemaStmt{ + Schemas: []*ast.String{ + { + Str: "schema10", + }, + }, + MissingOk: true, + }, + outStub: func(t *testing.T, newCatalog *Catalog, err error) { + + if err != nil { + t.Errorf("err should be nil, got: %v", err) + } + + if len(newCatalog.Schemas) != 5 { + t.Errorf("catalog schema length: want 5, got: %d", len(newCatalog.Schemas)) + } + }, + }, + { + name: "SchemaNotFound", + stmt: &ast.DropSchemaStmt{ + Schemas: []*ast.String{ + { + Str: "missing_schema", + }, + }, + }, + outStub: func(t *testing.T, newCatalog *Catalog, err error) { + + if err == nil { + t.Error("err should not nil") + } + + if len(newCatalog.Schemas) != 5 { + t.Errorf("catalog schema length: want 5, got: %d", len(newCatalog.Schemas)) + } + }, + }, + } + + for i := range testCases { + + tc := testCases[i] + + t.Run(tc.name, func(t *testing.T) { + + newCatalog := New("default") + + newCatalog.Schemas = append( + newCatalog.Schemas, + &Schema{Name: "schema1"}, + &Schema{Name: "schema2"}, + &Schema{Name: "schema3"}, + &Schema{Name: "schema4"}) + + err := newCatalog.dropSchema(tc.stmt) + tc.outStub(t, newCatalog, err) + }) + } +} diff --git a/internal/sql/catalog/table.go b/internal/sql/catalog/table.go index 2029a8bc13..780b718f5f 100644 --- a/internal/sql/catalog/table.go +++ b/internal/sql/catalog/table.go @@ -8,6 +8,10 @@ import ( "github.com/kyleconroy/sqlc/internal/sql/sqlerr" ) +// Table describes a relational database table +// +// A database table is a collection of related data held in a table format within a database. +// It consists of columns and rows. type Table struct { Rel *ast.TableName Columns []*Column diff --git a/internal/sql/catalog/table_test.go b/internal/sql/catalog/table_test.go new file mode 100644 index 0000000000..ecffd3e37e --- /dev/null +++ b/internal/sql/catalog/table_test.go @@ -0,0 +1,40 @@ +package catalog + +import ( + "testing" + + "github.com/kyleconroy/sqlc/internal/sql/ast" +) + +func TestGetTable(t *testing.T) { + + testCases := []struct { + name string + tableName *ast.TableName + outStub func(t *testing.T, outSchema *Schema, outTable *Table, err error) + }{ + { + name: "Use Catalog Default Schema", + tableName: &ast.TableName{ + Catalog: "catalog1", + Schema: "", + Name: "table1", + }, + outStub: func(t *testing.T, outSchema *Schema, outTable *Table, err error) { + + }, + }, + } + + newCatalog := New("default") + + for i := range testCases { + + tc := testCases[i] + + outSchema, outTable, err := newCatalog.getTable(tc.tableName) + + tc.outStub(t, outSchema, outTable, err) + + } +} From 71d434769a5d372fbcb5ebd331cb0018e0fbdc80 Mon Sep 17 00:00:00 2001 From: Songa Ogutu Date: Thu, 12 May 2022 07:51:05 +0300 Subject: [PATCH 3/7] Remove all unit test in favor of endtoend tests --- internal/sql/catalog/catalog_test.go | 30 -- internal/sql/catalog/func_test.go | 1 - internal/sql/catalog/schema_test.go | 758 --------------------------- internal/sql/catalog/table_test.go | 40 -- 4 files changed, 829 deletions(-) delete mode 100644 internal/sql/catalog/catalog_test.go delete mode 100644 internal/sql/catalog/func_test.go delete mode 100644 internal/sql/catalog/schema_test.go delete mode 100644 internal/sql/catalog/table_test.go diff --git a/internal/sql/catalog/catalog_test.go b/internal/sql/catalog/catalog_test.go deleted file mode 100644 index 3595d7cb63..0000000000 --- a/internal/sql/catalog/catalog_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package catalog - -import "testing" - -func TestNew(t *testing.T) { - - const defaultSchema = "default" - - newCatalog := New(defaultSchema) - - if newCatalog.DefaultSchema == "" { - t.Errorf("newCatalog.DefaultSchema: want %s, got %s", defaultSchema, newCatalog.DefaultSchema) - } - - if newCatalog.Schemas == nil { - t.Error("newCatalog.Schemas should not be nil") - } - - if len(newCatalog.Schemas) != 1 { - t.Errorf("newCatalog.Schemas length want 1, got %d", len(newCatalog.Schemas)) - } - - if newCatalog.Schemas[0].Name != defaultSchema { - t.Error("newCatalog.Schemas should have the default schema") - } - - if newCatalog.Extensions == nil { - t.Error("newCatalog.Extensions should be empty") - } -} diff --git a/internal/sql/catalog/func_test.go b/internal/sql/catalog/func_test.go deleted file mode 100644 index e571e24c61..0000000000 --- a/internal/sql/catalog/func_test.go +++ /dev/null @@ -1 +0,0 @@ -package catalog diff --git a/internal/sql/catalog/schema_test.go b/internal/sql/catalog/schema_test.go deleted file mode 100644 index be76e6adf3..0000000000 --- a/internal/sql/catalog/schema_test.go +++ /dev/null @@ -1,758 +0,0 @@ -package catalog - -import ( - "strings" - "testing" - - "github.com/kyleconroy/sqlc/internal/sql/ast" -) - -func TestSchemaGetFunc(t *testing.T) { - - testCases := []struct { - name string - rel *ast.FuncName - tns []*ast.TypeName - outStub func(t *testing.T, schema *Schema, schemaFunc *Function, funcIndex int, err error) - }{ - { - name: "FunctionFound", - rel: &ast.FuncName{ - Name: "func1", - Schema: "schema1", - }, - tns: []*ast.TypeName{ - { - Name: "type1", - Catalog: "catalog1", - Schema: "schema1", - }, - }, - outStub: func(t *testing.T, schema *Schema, schemaFunc *Function, funcIndex int, err error) { - - if funcIndex < 0 { - t.Errorf("invalid funcIndex want greater than 0 got: %d", funcIndex) - } - - if schema.Funcs[funcIndex].Name != schemaFunc.Name { - t.Errorf("schema function want: %s, got %s", schema.Funcs[funcIndex].Name, schemaFunc.Name) - } - - if err != nil { - t.Errorf("err should be nil got %v", err) - } - }, - }, - { - name: "FunctionAgumentMismatch", - rel: &ast.FuncName{ - Name: "func1", - Schema: "schema1", - }, - tns: []*ast.TypeName{ - { - Name: "type1", - Catalog: "catalog1", - Schema: "schema1", - }, - { - Name: "type2", - Catalog: "catalog1", - Schema: "schema1", - }, - }, - outStub: func(t *testing.T, schema *Schema, schemaFunc *Function, funcIndex int, err error) { - - if funcIndex > -1 { - t.Errorf("invalid funcIndex want less than 0 got: %d", funcIndex) - } - - if schemaFunc != nil { - t.Error("schema function should be nil") - } - - if err == nil { - t.Error("err should not be nil") - } - }, - }, - { - name: "FunctionNameMismatch", - rel: &ast.FuncName{ - Name: "func", - Schema: "schema1", - }, - tns: []*ast.TypeName{ - { - Name: "type1", - Catalog: "catalog1", - Schema: "schema1", - }, - }, - outStub: func(t *testing.T, schema *Schema, schemaFunc *Function, funcIndex int, err error) { - - if funcIndex > -1 { - t.Errorf("invalid funcIndex want less than 0 got: %d", funcIndex) - } - - if schemaFunc != nil { - t.Error("schema function should be nil") - } - - if err == nil { - t.Error("err should not be nil") - } - }, - }, - { - name: "SchemaNameMismatch", - rel: &ast.FuncName{ - Name: "func1", - Schema: "schema2", - }, - tns: []*ast.TypeName{ - { - Name: "type1", - Catalog: "catalog1", - Schema: "schema2", - }, - }, - outStub: func(t *testing.T, schema *Schema, schemaFunc *Function, funcIndex int, err error) { - - if funcIndex > -1 { - t.Errorf("invalid funcIndex want less than 0 got: %d", funcIndex) - } - - if schemaFunc != nil { - t.Error("schema function should be nil") - } - - if err == nil { - t.Error("err should not be nil") - } - }, - }, - } - - schema := &Schema{ - Name: "schema1", - Funcs: []*Function{ - { - Name: "func1", - Args: []*Argument{ - { - Name: "arg1", - Type: &ast.TypeName{ - Name: "type1", - Catalog: "catalog1", - Schema: "schema1", - }, - Mode: ast.FuncParamIn, - }, - }, - }, - { - Name: "func2", - Args: []*Argument{ - { - Name: "arg1", - Type: &ast.TypeName{ - Name: "type1", - Catalog: "catalog1", - Schema: "schema1", - }, - Mode: ast.FuncParamIn, - }, - }, - }, - }, - } - - for i := range testCases { - - tc := testCases[i] - - t.Run(tc.name, func(t *testing.T) { - outFunc, outIndex, err := schema.getFunc(tc.rel, tc.tns) - tc.outStub(t, schema, outFunc, outIndex, err) - }) - } -} - -func TestSchemaGetFuncByName(t *testing.T) { - - schema := &Schema{ - Name: "schema1", - Funcs: []*Function{ - { - Name: "func1", - Args: []*Argument{ - { - Name: "arg1", - Type: &ast.TypeName{ - Name: "type1", - Catalog: "catalog1", - Schema: "schema1", - }, - Mode: ast.FuncParamIn, - }, - }, - }, - { - Name: "func2", - Args: []*Argument{ - { - Name: "arg1", - Type: &ast.TypeName{ - Name: "type1", - Catalog: "catalog1", - Schema: "schema1", - }, - Mode: ast.FuncParamIn, - }, - }, - }, - }, - } - - testCases := []struct { - name string - schema *Schema - rel *ast.FuncName - outStub func(t *testing.T, schema *Schema, schemaFunc *Function, funcIndex int, err error) - }{ - { - name: "FunctionFound", - schema: schema, - rel: &ast.FuncName{ - Name: "func1", - Schema: "schema1", - }, - outStub: func(t *testing.T, schema *Schema, schemaFunc *Function, funcIndex int, err error) { - - if funcIndex < 0 { - t.Errorf("invalid funcIndex want greater than 0 got: %d", funcIndex) - } - - if schema.Funcs[funcIndex].Name != schemaFunc.Name { - t.Errorf("schema function want: %s, got %s", schema.Funcs[funcIndex].Name, schemaFunc.Name) - } - - if err != nil { - t.Errorf("err should be nil got %v", err) - } - }, - }, - { - name: "FunctionNotUnique", - schema: func() *Schema { - - // Create a new schema - - newSchema := Schema{} - newSchema = *schema - - // Add a duplicate func for test - newSchema.Funcs = append(newSchema.Funcs, &Function{ - Name: "func1", - Args: []*Argument{ - { - Name: "arg1", - Type: &ast.TypeName{ - Name: "type1", - Catalog: "catalog1", - Schema: "schema1", - }, - Mode: ast.FuncParamIn, - }, - }, - }) - - return &newSchema - }(), - rel: &ast.FuncName{ - Name: "func1", - Schema: "schema1", - }, - outStub: func(t *testing.T, schema *Schema, schemaFunc *Function, funcIndex int, err error) { - - if funcIndex > -1 { - t.Errorf("invalid funcIndex want less than 0 got: %d", funcIndex) - } - - if schemaFunc != nil { - t.Error("schema function should be nil") - } - - if err == nil { - t.Error("err should not be nil") - } - }, - }, - { - name: "FunctionNotFound", - schema: schema, - rel: &ast.FuncName{ - Name: "func", - Schema: "schema1", - }, - outStub: func(t *testing.T, schema *Schema, schemaFunc *Function, funcIndex int, err error) { - - if funcIndex > -1 { - t.Errorf("invalid funcIndex want less than 0 got: %d", funcIndex) - } - - if schemaFunc != nil { - t.Error("schema function should be nil") - } - - if err == nil { - t.Error("err should not be nil") - } - }, - }, - } - - for i := range testCases { - - tc := testCases[i] - - t.Run(tc.name, func(t *testing.T) { - outFunc, outIndex, err := tc.schema.getFuncByName(tc.rel) - tc.outStub(t, tc.schema, outFunc, outIndex, err) - }) - } -} - -func TestSchemaGetTable(t *testing.T) { - - schema := &Schema{ - Name: "schema1", - Tables: []*Table{ - { - Rel: &ast.TableName{ - Name: "table1", - }, - }, - { - Rel: &ast.TableName{ - Name: "table2", - }, - }, - }, - } - - testCases := []struct { - name string - rel *ast.TableName - outStub func(t *testing.T, schema *Schema, schemaFunc *Table, tableIndex int, err error) - }{ - { - name: "TableFound", - rel: &ast.TableName{ - Name: "table2", - }, - outStub: func(t *testing.T, schema *Schema, schemaTable *Table, tableIndex int, err error) { - - if tableIndex < 0 { - t.Errorf("invalid tableIndex want greater than 0 got: %d", tableIndex) - } - - if schema.Tables[tableIndex].Rel.Name != schemaTable.Rel.Name { - t.Errorf("schema table want: %s, got %s", schema.Tables[tableIndex].Rel.Name, schemaTable.Rel.Name) - } - - if err != nil { - t.Errorf("err should be nil got %v", err) - } - }, - }, - { - name: "TableNotFound", - rel: &ast.TableName{ - Name: "table", - }, - outStub: func(t *testing.T, schema *Schema, schemaTable *Table, tableIndex int, err error) { - - if tableIndex > -1 { - t.Errorf("invalid tableIndex want less than 0 got: %d", tableIndex) - } - - if schemaTable != nil { - t.Error("schema table should be nil") - } - - if err == nil { - t.Error("err should not be nil") - } - }, - }, - } - - for i := range testCases { - - tc := testCases[i] - - t.Run(tc.name, func(t *testing.T) { - outTable, outIndex, err := schema.getTable(tc.rel) - tc.outStub(t, schema, outTable, outIndex, err) - }) - } -} - -func TestSchemaGetType(t *testing.T) { - - schema := &Schema{ - Name: "schema1", - Types: []Type{ - &Enum{ - Name: "emum1", - }, - &Enum{ - Name: "emum2", - }, - &CompositeType{ - Name: "compositeType1", - }, - }, - } - - testCases := []struct { - name string - rel *ast.TypeName - outStub func(t *testing.T, schema *Schema, schemaEnum Type, typeIndex int, err error) - }{ - { - name: "TypeFound", - rel: &ast.TypeName{ - Name: "emum1", - }, - outStub: func(t *testing.T, schema *Schema, schemaType Type, typeIndex int, err error) { - - if typeIndex < 0 { - t.Errorf("invalid typeIndex want greater than 0 got: %d", typeIndex) - } - - if schemaType == nil { - t.Error("schema type should not be nil") - } - - if err != nil { - t.Errorf("err should be nil got %v", err) - } - }, - }, - { - name: "TypeNotFound", - rel: &ast.TypeName{ - Name: "enum", - }, - outStub: func(t *testing.T, schema *Schema, schemaType Type, typeIndex int, err error) { - - if typeIndex > -1 { - t.Errorf("invalid typeIndex want greater than 0 got: %d", typeIndex) - } - - if schemaType != nil { - t.Error("schema type should not be nil") - } - - if err == nil { - t.Error("err should not be nil") - } - }, - }, - { - name: "TypeInvalid", - rel: &ast.TypeName{ - Name: "compositeType1", - }, - outStub: func(t *testing.T, schema *Schema, schemaType Type, typeIndex int, err error) { - - if typeIndex > -1 { - t.Errorf("invalid typeIndex want greater than 0 got: %d", typeIndex) - } - - if schemaType != nil { - t.Error("schema type should not be nil") - } - - if err == nil { - t.Error("err should not be nil") - } - }, - }, - } - - for i := range testCases { - - tc := testCases[i] - - t.Run(tc.name, func(t *testing.T) { - outType, outIndex, err := schema.getType(tc.rel) - tc.outStub(t, schema, outType, outIndex, err) - }) - } -} - -func TestGetSchema(t *testing.T) { - - testCases := []struct { - name string - schemaName string - outStub func(t *testing.T, outSchema *Schema, err error) - }{ - { - name: "Schema Found", - schemaName: "default", - outStub: func(t *testing.T, schema *Schema, err error) { - - if schema.Name != "default" { - t.Errorf("schema name want default got %s", schema.Name) - } - - if err != nil { - t.Errorf("err should be nil got %v", err) - } - }, - }, - { - name: "Schema Not Found", - schemaName: "wrongSchema", - outStub: func(t *testing.T, schema *Schema, err error) { - - if schema != nil { - t.Error("should be nil") - } - - if err == nil { - t.Error("err should not be nil") - } - }, - }, - } - - newCatalog := New("default") - - for i := range testCases { - - tc := testCases[i] - - t.Run(tc.name, func(t *testing.T) { - outSchema, err := newCatalog.getSchema(tc.schemaName) - tc.outStub(t, outSchema, err) - }) - } -} - -func TestCreteSchema(t *testing.T) { - - testCases := []struct { - name string - stmt *ast.CreateSchemaStmt - outStub func(t *testing.T, newCatalog *Catalog, err error) - }{ - { - name: "No Schema Name", - stmt: func() *ast.CreateSchemaStmt { - return &ast.CreateSchemaStmt{ - Name: nil, - } - }(), - outStub: func(t *testing.T, newCatalog *Catalog, err error) { - - if !strings.Contains(err.Error(), "empty name") { - t.Errorf("should contain phrase: empty name, got: %s", err.Error()) - } - - if len(newCatalog.Schemas) != 1 { - t.Errorf("catalog schema length: want 1, got: %d", len(newCatalog.Schemas)) - } - }, - }, - { - name: "Schema Name Exists", - stmt: func() *ast.CreateSchemaStmt { - - schemaName := "default" - - return &ast.CreateSchemaStmt{ - Name: &schemaName, - } - }(), - outStub: func(t *testing.T, newCatalog *Catalog, err error) { - - if err == nil { - t.Error("should not be nil") - } - - if len(newCatalog.Schemas) != 1 { - t.Errorf("catalog schema length: want 1, got: %d", len(newCatalog.Schemas)) - } - }, - }, - { - name: "Schema Created", - stmt: func() *ast.CreateSchemaStmt { - - schemaName := "new_schema" - - return &ast.CreateSchemaStmt{ - Name: &schemaName, - } - }(), - outStub: func(t *testing.T, newCatalog *Catalog, err error) { - - if err != nil { - t.Errorf("should be nil got: %v", err) - } - - if len(newCatalog.Schemas) != 2 { - t.Errorf("catalog schema length: want 2, got: %d", len(newCatalog.Schemas)) - } - }, - }, - } - - newCatalog := New("default") - - for i := range testCases { - - tc := testCases[i] - - t.Run(tc.name, func(t *testing.T) { - err := newCatalog.createSchema(tc.stmt) - tc.outStub(t, newCatalog, err) - }) - } -} - -func TestDropSchema(t *testing.T) { - - testCases := []struct { - name string - stmt *ast.DropSchemaStmt - outStub func(t *testing.T, newCatalog *Catalog, err error) - }{ - { - name: "NoSchemaProvided", - stmt: &ast.DropSchemaStmt{ - Schemas: nil, - }, - outStub: func(t *testing.T, newCatalog *Catalog, err error) { - - if err != nil { - t.Errorf("err should be nil, got: %v", err) - } - - if len(newCatalog.Schemas) != 5 { - t.Errorf("catalog schema length: want 5, got: %d", len(newCatalog.Schemas)) - } - }, - }, - { - name: "DeleteOneSchema", - stmt: &ast.DropSchemaStmt{ - Schemas: []*ast.String{ - { - Str: "schema1", - }, - }, - }, - outStub: func(t *testing.T, newCatalog *Catalog, err error) { - - if err != nil { - t.Errorf("err should be nil, got: %v", err) - } - - if len(newCatalog.Schemas) != 4 { - t.Errorf("catalog schema length: want 4, got: %d", len(newCatalog.Schemas)) - } - }, - }, - { - name: "DeleteMultipleSchema", - stmt: &ast.DropSchemaStmt{ - Schemas: []*ast.String{ - { - Str: "schema1", - }, - { - Str: "schema3", - }, - }, - }, - outStub: func(t *testing.T, newCatalog *Catalog, err error) { - - if err != nil { - t.Errorf("err should be nil, got: %v", err) - } - - if len(newCatalog.Schemas) != 3 { - t.Errorf("catalog schema length: want 3, got: %d", len(newCatalog.Schemas)) - } - }, - }, - { - name: "AllowedMissingSchema", - stmt: &ast.DropSchemaStmt{ - Schemas: []*ast.String{ - { - Str: "schema10", - }, - }, - MissingOk: true, - }, - outStub: func(t *testing.T, newCatalog *Catalog, err error) { - - if err != nil { - t.Errorf("err should be nil, got: %v", err) - } - - if len(newCatalog.Schemas) != 5 { - t.Errorf("catalog schema length: want 5, got: %d", len(newCatalog.Schemas)) - } - }, - }, - { - name: "SchemaNotFound", - stmt: &ast.DropSchemaStmt{ - Schemas: []*ast.String{ - { - Str: "missing_schema", - }, - }, - }, - outStub: func(t *testing.T, newCatalog *Catalog, err error) { - - if err == nil { - t.Error("err should not nil") - } - - if len(newCatalog.Schemas) != 5 { - t.Errorf("catalog schema length: want 5, got: %d", len(newCatalog.Schemas)) - } - }, - }, - } - - for i := range testCases { - - tc := testCases[i] - - t.Run(tc.name, func(t *testing.T) { - - newCatalog := New("default") - - newCatalog.Schemas = append( - newCatalog.Schemas, - &Schema{Name: "schema1"}, - &Schema{Name: "schema2"}, - &Schema{Name: "schema3"}, - &Schema{Name: "schema4"}) - - err := newCatalog.dropSchema(tc.stmt) - tc.outStub(t, newCatalog, err) - }) - } -} diff --git a/internal/sql/catalog/table_test.go b/internal/sql/catalog/table_test.go deleted file mode 100644 index ecffd3e37e..0000000000 --- a/internal/sql/catalog/table_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package catalog - -import ( - "testing" - - "github.com/kyleconroy/sqlc/internal/sql/ast" -) - -func TestGetTable(t *testing.T) { - - testCases := []struct { - name string - tableName *ast.TableName - outStub func(t *testing.T, outSchema *Schema, outTable *Table, err error) - }{ - { - name: "Use Catalog Default Schema", - tableName: &ast.TableName{ - Catalog: "catalog1", - Schema: "", - Name: "table1", - }, - outStub: func(t *testing.T, outSchema *Schema, outTable *Table, err error) { - - }, - }, - } - - newCatalog := New("default") - - for i := range testCases { - - tc := testCases[i] - - outSchema, outTable, err := newCatalog.getTable(tc.tableName) - - tc.outStub(t, outSchema, outTable, err) - - } -} From 3db8cbbda88df0eaf80a85053e594467dce1768d Mon Sep 17 00:00:00 2001 From: Songa Ogutu Date: Thu, 12 May 2022 08:13:30 +0300 Subject: [PATCH 4/7] Refactor catalog getTable to improve readability --- internal/sql/catalog/catalog.go | 15 ++- internal/sql/catalog/table.go | 209 ++++++++++++++++++++------------ 2 files changed, 139 insertions(+), 85 deletions(-) diff --git a/internal/sql/catalog/catalog.go b/internal/sql/catalog/catalog.go index 699865c74a..798a636d8c 100644 --- a/internal/sql/catalog/catalog.go +++ b/internal/sql/catalog/catalog.go @@ -19,13 +19,18 @@ type Catalog struct { // New creates a new catalog func New(defaultSchema string) *Catalog { - return &Catalog{ + + newCatalog := &Catalog{ DefaultSchema: defaultSchema, - Schemas: []*Schema{ - {Name: defaultSchema}, - }, - Extensions: make(map[string]struct{}), + Schemas: make([]*Schema, 0), + Extensions: make(map[string]struct{}), + } + + if newCatalog.DefaultSchema != "" { + newCatalog.Schemas = append(newCatalog.Schemas, &Schema{Name: defaultSchema}) } + + return newCatalog } func (c *Catalog) Build(stmts []ast.Statement) error { diff --git a/internal/sql/catalog/table.go b/internal/sql/catalog/table.go index 780b718f5f..2b9df6597e 100644 --- a/internal/sql/catalog/table.go +++ b/internal/sql/catalog/table.go @@ -18,6 +18,100 @@ type Table struct { Comment string } +func (table *Table) isExistColumn(cmd *ast.AlterTableCmd) (int, error) { + + for i, c := range table.Columns { + if c.Name == *cmd.Name { + return i, nil + } + } + + if !cmd.MissingOk { + return -1, sqlerr.ColumnNotFound(table.Rel.Name, *cmd.Name) + } + + // Missing column is allowed + return -1, nil +} + +func (table *Table) addColumn(cmd *ast.AlterTableCmd) error { + + for _, c := range table.Columns { + if c.Name == cmd.Def.Colname { + return sqlerr.ColumnExists(table.Rel.Name, c.Name) + } + } + + table.Columns = append(table.Columns, &Column{ + Name: cmd.Def.Colname, + Type: *cmd.Def.TypeName, + IsNotNull: cmd.Def.IsNotNull, + IsArray: cmd.Def.IsArray, + Length: cmd.Def.Length, + }) + + return nil +} + +func (table *Table) alterColumnType(cmd *ast.AlterTableCmd) error { + + index, err := table.isExistColumn(cmd) + if err != nil { + return err + } + + if index >= 0 { + table.Columns[index].Type = *cmd.Def.TypeName + table.Columns[index].IsArray = cmd.Def.IsArray + } + + return nil +} + +func (table *Table) dropColumn(cmd *ast.AlterTableCmd) error { + + index, err := table.isExistColumn(cmd) + if err != nil { + return err + } + + if index >= 0 { + table.Columns = append(table.Columns[:index], table.Columns[index+1:]...) + } + + return nil +} + +func (table *Table) dropNotNull(cmd *ast.AlterTableCmd) error { + + index, err := table.isExistColumn(cmd) + if err != nil { + return err + } + + if index >= 0 { + table.Columns[index].IsNotNull = false + } + + return nil +} + +func (table *Table) setNotNull(cmd *ast.AlterTableCmd) error { + + index, err := table.isExistColumn(cmd) + if err != nil { + return err + } + + if index >= 0 { + table.Columns[index].IsNotNull = true + } + + return nil +} + +// Column describes a set of data values of a particular type in a relational database table +// // TODO: Should this just be ast Nodes? type Column struct { Name string @@ -35,114 +129,69 @@ type columnGenerator interface { OutputColumns(node ast.Node) ([]*Column, error) } -func (c *Catalog) getTable(name *ast.TableName) (*Schema, *Table, error) { - ns := name.Schema - if ns == "" { - ns = c.DefaultSchema +func (c *Catalog) getTable(tableName *ast.TableName) (*Schema, *Table, error) { + + schemaName := tableName.Schema + + if schemaName == "" { + schemaName = c.DefaultSchema } - var s *Schema + + var schema *Schema + for i := range c.Schemas { - if c.Schemas[i].Name == ns { - s = c.Schemas[i] + if c.Schemas[i].Name == schemaName { + schema = c.Schemas[i] break } } - if s == nil { - return nil, nil, sqlerr.SchemaNotFound(ns) + + if schema == nil { + return nil, nil, sqlerr.SchemaNotFound(schemaName) } - t, _, err := s.getTable(name) + + table, _, err := schema.getTable(tableName) if err != nil { return nil, nil, err } - return s, t, nil + + return schema, table, nil } func (c *Catalog) alterTable(stmt *ast.AlterTableStmt) error { - var implemented bool - for _, item := range stmt.Cmds.Items { - switch cmd := item.(type) { - case *ast.AlterTableCmd: - switch cmd.Subtype { - case ast.AT_AddColumn: - implemented = true - case ast.AT_AlterColumnType: - implemented = true - case ast.AT_DropColumn: - implemented = true - case ast.AT_DropNotNull: - implemented = true - case ast.AT_SetNotNull: - implemented = true - } - } - } - if !implemented { - return nil - } + _, table, err := c.getTable(stmt.Table) if err != nil { return err } - for _, cmd := range stmt.Cmds.Items { - switch cmd := cmd.(type) { + for _, item := range stmt.Cmds.Items { + switch cmd := item.(type) { case *ast.AlterTableCmd: - idx := -1 - - // Lookup column names for column-related commands switch cmd.Subtype { - case ast.AT_AlterColumnType, - ast.AT_DropColumn, - ast.AT_DropNotNull, - ast.AT_SetNotNull: - for i, c := range table.Columns { - if c.Name == *cmd.Name { - idx = i - break - } - } - if idx < 0 && !cmd.MissingOk { - return sqlerr.ColumnNotFound(table.Rel.Name, *cmd.Name) - } - // If a missing column is allowed, skip this command - if idx < 0 && cmd.MissingOk { - continue - } - } - - switch cmd.Subtype { - case ast.AT_AddColumn: - for _, c := range table.Columns { - if c.Name == cmd.Def.Colname { - return sqlerr.ColumnExists(table.Rel.Name, c.Name) - } + if err := table.addColumn(cmd); err != nil { + return err } - table.Columns = append(table.Columns, &Column{ - Name: cmd.Def.Colname, - Type: *cmd.Def.TypeName, - IsNotNull: cmd.Def.IsNotNull, - IsArray: cmd.Def.IsArray, - Length: cmd.Def.Length, - }) - case ast.AT_AlterColumnType: - table.Columns[idx].Type = *cmd.Def.TypeName - table.Columns[idx].IsArray = cmd.Def.IsArray - + if err := table.alterColumnType(cmd); err != nil { + return err + } case ast.AT_DropColumn: - table.Columns = append(table.Columns[:idx], table.Columns[idx+1:]...) - + if err := table.dropColumn(cmd); err != nil { + return err + } case ast.AT_DropNotNull: - table.Columns[idx].IsNotNull = false - + if err := table.dropNotNull(cmd); err != nil { + return err + } case ast.AT_SetNotNull: - table.Columns[idx].IsNotNull = true - + if err := table.setNotNull(cmd); err != nil { + return err + } } } } - return nil } From 19a4eb3bbd36abb9588de99a54886d53b751647e Mon Sep 17 00:00:00 2001 From: Songa Ogutu Date: Fri, 13 May 2022 12:53:40 +0300 Subject: [PATCH 5/7] Add endtoend test data for add table column --- .../ddl_alter_table_add_column/mysql/go/db.go | 31 ++++++++++++++++++ .../mysql/go/models.go | 15 +++++++++ .../mysql/go/query.sql.go | 19 +++++++++++ .../mysql/query.sql | 2 ++ .../mysql/schema.sql | 3 ++ .../mysql/sqlc.json | 12 +++++++ .../postgresql/pgx/go/db.go | 32 +++++++++++++++++++ .../postgresql/pgx/go/models.go | 15 +++++++++ .../postgresql/pgx/go/query.sql.go | 19 +++++++++++ .../postgresql/pgx/query.sql | 2 ++ .../postgresql/pgx/schema.sql | 3 ++ .../postgresql/pgx/sqlc.json | 13 ++++++++ .../postgresql/stdlib/go/db.go | 31 ++++++++++++++++++ .../postgresql/stdlib/go/models.go | 15 +++++++++ .../postgresql/stdlib/go/query.sql.go | 19 +++++++++++ .../postgresql/stdlib/query.sql | 2 ++ .../postgresql/stdlib/schema.sql | 3 ++ .../postgresql/stdlib/sqlc.json | 12 +++++++ 18 files changed, 248 insertions(+) create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/mysql/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/mysql/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/mysql/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/sqlc.json diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/db.go b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/db.go new file mode 100644 index 0000000000..36ef5f4f45 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.13.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/models.go b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/models.go new file mode 100644 index 0000000000..771d118790 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.13.0 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar string + Baz sql.NullInt32 + Bio sql.NullInt32 +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/query.sql.go new file mode 100644 index 0000000000..6070d0b2f4 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.13.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/query.sql b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/query.sql new file mode 100644 index 0000000000..bb628f9251 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: Placeholder :exec */ +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/schema.sql b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/schema.sql new file mode 100644 index 0000000000..0019a393a2 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (bar text NOT NULL); +ALTER TABLE foo ADD COLUMN baz integer; +ALTER TABLE foo ADD bio integer; \ No newline at end of file diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/sqlc.json new file mode 100644 index 0000000000..e41c39e8b3 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "mysql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/go/db.go b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/go/db.go new file mode 100644 index 0000000000..b0157bd009 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.13.0 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) + Query(context.Context, string, ...interface{}) (pgx.Rows, error) + QueryRow(context.Context, string, ...interface{}) pgx.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx pgx.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/go/models.go b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/go/models.go new file mode 100644 index 0000000000..771d118790 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.13.0 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar string + Baz sql.NullInt32 + Bio sql.NullInt32 +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000000..98f12b1d40 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.13.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/query.sql b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/query.sql new file mode 100644 index 0000000000..6520aef4b6 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/schema.sql b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/schema.sql new file mode 100644 index 0000000000..01c3f60d0f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (bar text NOT NULL); +ALTER TABLE foo ADD COLUMN baz int; +ALTER TABLE foo ADD bio int; diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/sqlc.json new file mode 100644 index 0000000000..d1244c9e7a --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/pgx/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/db.go new file mode 100644 index 0000000000..36ef5f4f45 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.13.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/models.go new file mode 100644 index 0000000000..771d118790 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/models.go @@ -0,0 +1,15 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.13.0 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar string + Baz sql.NullInt32 + Bio sql.NullInt32 +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000000..6070d0b2f4 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.13.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/query.sql new file mode 100644 index 0000000000..6520aef4b6 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/schema.sql new file mode 100644 index 0000000000..01c3f60d0f --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (bar text NOT NULL); +ALTER TABLE foo ADD COLUMN baz int; +ALTER TABLE foo ADD bio int; diff --git a/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000000..f717ca2e66 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_add_column/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} From 434eba3764777307d769110d1a0f7d739e281192 Mon Sep 17 00:00:00 2001 From: Songa Ogutu Date: Fri, 13 May 2022 13:21:36 +0300 Subject: [PATCH 6/7] Add endtoend test for mysql alter column type --- .../ddl_alter_table_alter_type/mysql/go/db.go | 31 +++++++++++++++++++ .../mysql/go/models.go | 14 +++++++++ .../mysql/go/query.sql.go | 19 ++++++++++++ .../mysql/query.sql | 2 ++ .../mysql/schema.sql | 3 ++ .../mysql/sqlc.json | 12 +++++++ 6 files changed, 81 insertions(+) create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/sqlc.json diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/db.go b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/db.go new file mode 100644 index 0000000000..36ef5f4f45 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.13.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/models.go b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/models.go new file mode 100644 index 0000000000..7c85bddf45 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/models.go @@ -0,0 +1,14 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.13.0 + +package querytest + +import ( + "database/sql" +) + +type Foo struct { + Bar sql.NullInt32 + Baz sql.NullInt32 +} diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/query.sql.go new file mode 100644 index 0000000000..6070d0b2f4 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.13.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/query.sql b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/query.sql new file mode 100644 index 0000000000..bb628f9251 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/query.sql @@ -0,0 +1,2 @@ +/* name: Placeholder :exec */ +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/schema.sql b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/schema.sql new file mode 100644 index 0000000000..a81bc00990 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/schema.sql @@ -0,0 +1,3 @@ +CREATE TABLE foo (bar text NOT NULL, baz text NOT NULL); +ALTER TABLE foo MODIFY COLUMN bar integer; +ALTER TABLE foo MODIFY baz integer; diff --git a/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/sqlc.json new file mode 100644 index 0000000000..e41c39e8b3 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_alter_type/mysql/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "mysql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} From 7b98e978f9ac4899a4657f985cf14194fa698268 Mon Sep 17 00:00:00 2001 From: Songa Ogutu Date: Fri, 13 May 2022 13:28:03 +0300 Subject: [PATCH 7/7] Add endtoend testdata for postgresql rename column --- .../postgresql/pgx/go/db.go | 32 +++++++++++++++++++ .../postgresql/pgx/go/models.go | 11 +++++++ .../postgresql/pgx/go/query.sql.go | 19 +++++++++++ .../postgresql/pgx/query.sql | 2 ++ .../postgresql/pgx/schema.sql | 2 ++ .../postgresql/pgx/sqlc.json | 13 ++++++++ .../postgresql/stdlib/go/db.go | 31 ++++++++++++++++++ .../postgresql/stdlib/go/models.go | 11 +++++++ .../postgresql/stdlib/go/query.sql.go | 19 +++++++++++ .../postgresql/stdlib/query.sql | 2 ++ .../postgresql/stdlib/schema.sql | 2 ++ .../postgresql/stdlib/sqlc.json | 12 +++++++ 12 files changed, 156 insertions(+) create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/sqlc.json diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/go/db.go b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/go/db.go new file mode 100644 index 0000000000..b0157bd009 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.13.0 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) + Query(context.Context, string, ...interface{}) (pgx.Rows, error) + QueryRow(context.Context, string, ...interface{}) pgx.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx pgx.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/go/models.go b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/go/models.go new file mode 100644 index 0000000000..d4b8977f56 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/go/models.go @@ -0,0 +1,11 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.13.0 + +package querytest + +import () + +type Foo struct { + Baz string +} diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/go/query.sql.go new file mode 100644 index 0000000000..98f12b1d40 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.13.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.Exec(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/query.sql b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/query.sql new file mode 100644 index 0000000000..6520aef4b6 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/schema.sql b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/schema.sql new file mode 100644 index 0000000000..501fc0c0f4 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text NOT NULL); +ALTER TABLE foo RENAME COLUMN bar TO baz; diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/sqlc.json new file mode 100644 index 0000000000..d1244c9e7a --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/pgx/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/db.go new file mode 100644 index 0000000000..36ef5f4f45 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.13.0 + +package querytest + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/models.go new file mode 100644 index 0000000000..d4b8977f56 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/models.go @@ -0,0 +1,11 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.13.0 + +package querytest + +import () + +type Foo struct { + Baz string +} diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000000..6070d0b2f4 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,19 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.13.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const placeholder = `-- name: Placeholder :exec +SELECT 1 +` + +func (q *Queries) Placeholder(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, placeholder) + return err +} diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/query.sql new file mode 100644 index 0000000000..6520aef4b6 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/query.sql @@ -0,0 +1,2 @@ +-- name: Placeholder :exec +SELECT 1; diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/schema.sql new file mode 100644 index 0000000000..501fc0c0f4 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/schema.sql @@ -0,0 +1,2 @@ +CREATE TABLE foo (bar text NOT NULL); +ALTER TABLE foo RENAME COLUMN bar TO baz; diff --git a/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000000..f717ca2e66 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_change_column/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +}