Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ toolchain go1.24.3

require (
github.com/Masterminds/squirrel v1.5.4
github.com/goravel/framework v1.15.2-0.20250513024952-5c6bf415f2ed
github.com/goravel/framework v1.15.2-0.20250523025922-88c15e8bda02
github.com/spf13/cast v1.8.0
github.com/stretchr/testify v1.10.0
gorm.io/driver/postgres v1.5.11
Expand All @@ -23,7 +23,7 @@ require (
github.com/dave/dst v0.27.3 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dromara/carbon/v2 v2.6.4 // indirect
github.com/dromara/carbon/v2 v2.6.6 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
Expand Down Expand Up @@ -75,8 +75,8 @@ require (
golang.org/x/term v0.32.0 // indirect
golang.org/x/text v0.25.0 // indirect
golang.org/x/tools v0.33.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 // indirect
google.golang.org/grpc v1.72.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250505200425-f936aa4a68b2 // indirect
google.golang.org/grpc v1.72.1 // indirect
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dromara/carbon/v2 v2.6.4 h1:cpIansyiEIEed3OlEIqo1IXj86qu0x6pf/E2keL2wYo=
github.com/dromara/carbon/v2 v2.6.4/go.mod h1:Baj3A1uBBctJmpZWJd6/+WWnmIuY2pobR6IOpB6xigc=
github.com/dromara/carbon/v2 v2.6.6/go.mod h1:7GXqCUplwN1s1b4whGk2zX4+g4CMCoDIZzmjlyt0vLY=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
Expand Down Expand Up @@ -147,6 +148,8 @@ github.com/goravel/framework v1.15.2-0.20250512040745-cf77c8a8e8c0 h1:ajQElV0Ieo
github.com/goravel/framework v1.15.2-0.20250512040745-cf77c8a8e8c0/go.mod h1:8guNAbVJAc08KttpkwSPBUvVnbGWkoRDO8QIRoAL3f8=
github.com/goravel/framework v1.15.2-0.20250513024952-5c6bf415f2ed h1:GHtrocwQ7MmEXgDf9K6vM6KBcT1nbvuyEmQVra7b4N4=
github.com/goravel/framework v1.15.2-0.20250513024952-5c6bf415f2ed/go.mod h1:8guNAbVJAc08KttpkwSPBUvVnbGWkoRDO8QIRoAL3f8=
github.com/goravel/framework v1.15.2-0.20250523025922-88c15e8bda02 h1:7uPGKrApEH+uc9t8HN0D1Qwz/rJw4xBlI1B5SY09VPo=
github.com/goravel/framework v1.15.2-0.20250523025922-88c15e8bda02/go.mod h1:dJtMqSQaFcIoICTmCgkNooq5ax+BUn5OF/60UfbtJT8=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
Expand Down Expand Up @@ -408,8 +411,10 @@ google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34 h1:
google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34/go.mod h1:0awUlEkap+Pb1UMeJwJQQAdJQrt3moU7J2moTy69irI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 h1:h6p3mQqrmT1XkHVTfzLdNz1u7IhINeZkz67/xTbOuWs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM=
google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
51 changes: 44 additions & 7 deletions grammar.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ func NewGrammar(prefix string) *Grammar {
grammar.ModifyDefault,
grammar.ModifyIncrement,
grammar.ModifyNullable,
grammar.ModifyGeneratedAsForChange,
grammar.ModifyGeneratedAs,
}

return grammar
Expand Down Expand Up @@ -435,9 +437,9 @@ func (r *Grammar) GetAttributeCommands() []string {
return r.attributeCommands
}

func (r *Grammar) ModifyDefault(blueprint driver.Blueprint, column driver.ColumnDefinition) string {
func (r *Grammar) ModifyDefault(_ driver.Blueprint, column driver.ColumnDefinition) string {
if column.IsChange() {
if column.GetAutoIncrement() {
if column.GetAutoIncrement() || column.IsSetGeneratedAs() {
return ""
}
if column.GetDefault() != nil {
Expand All @@ -452,7 +454,39 @@ func (r *Grammar) ModifyDefault(blueprint driver.Blueprint, column driver.Column
return ""
}

func (r *Grammar) ModifyNullable(blueprint driver.Blueprint, column driver.ColumnDefinition) string {
func (r *Grammar) ModifyGeneratedAs(_ driver.Blueprint, column driver.ColumnDefinition) string {
if !column.IsSetGeneratedAs() {
return ""
}

option := "by default"
if column.IsAlways() {
option = "always"
}

identity := ""
if generatedAs := column.GetGeneratedAs(); len(generatedAs) > 0 {
identity = " (" + generatedAs + ")"
}

sql := fmt.Sprintf(" generated %s as identity%s", option, identity)
if column.IsChange() {
sql = " add" + sql
}

return sql

}

func (r *Grammar) ModifyGeneratedAsForChange(_ driver.Blueprint, column driver.ColumnDefinition) string {
Comment thread
hwbrzzl marked this conversation as resolved.
if column.IsChange() && column.IsSetGeneratedAs() && !column.GetAutoIncrement() {
return " drop identity if exists"
}

return ""
}

func (r *Grammar) ModifyNullable(_ driver.Blueprint, column driver.ColumnDefinition) string {
if column.IsChange() {
if column.GetNullable() {
return " drop not null"
Expand All @@ -466,15 +500,18 @@ func (r *Grammar) ModifyNullable(blueprint driver.Blueprint, column driver.Colum
}

func (r *Grammar) ModifyIncrement(blueprint driver.Blueprint, column driver.ColumnDefinition) string {
if !column.IsChange() && !blueprint.HasCommand("primary") && slices.Contains(r.serials, column.GetType()) && column.GetAutoIncrement() {
if !column.IsChange() &&
!blueprint.HasCommand("primary") &&
(slices.Contains(r.serials, column.GetType()) || column.IsSetGeneratedAs()) &&
column.GetAutoIncrement() {
return " primary key"
}

return ""
}

func (r *Grammar) TypeBigInteger(column driver.ColumnDefinition) string {
if column.GetAutoIncrement() {
if column.GetAutoIncrement() && !column.IsChange() && !column.IsSetGeneratedAs() {
return "bigserial"
}

Expand Down Expand Up @@ -528,7 +565,7 @@ func (r *Grammar) TypeFloat(column driver.ColumnDefinition) string {
}

func (r *Grammar) TypeInteger(column driver.ColumnDefinition) string {
if column.GetAutoIncrement() {
if column.GetAutoIncrement() && !column.IsChange() && !column.IsSetGeneratedAs() {
return "serial"
}

Expand Down Expand Up @@ -556,7 +593,7 @@ func (r *Grammar) TypeMediumText(column driver.ColumnDefinition) string {
}

func (r *Grammar) TypeSmallInteger(column driver.ColumnDefinition) string {
if column.GetAutoIncrement() {
if column.GetAutoIncrement() && !column.IsChange() && !column.IsSetGeneratedAs() {
return "smallserial"
}

Expand Down
108 changes: 102 additions & 6 deletions grammar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ func (s *GrammarSuite) TestCompileAdd() {
mockColumn.EXPECT().GetDefault().Return("goravel").Twice()
mockColumn.EXPECT().GetNullable().Return(false).Once()
mockColumn.EXPECT().GetLength().Return(1).Once()
mockColumn.EXPECT().IsChange().Return(false).Times(3)
mockColumn.EXPECT().IsChange().Return(false).Times(4)
mockColumn.EXPECT().IsSetGeneratedAs().Return(false).Twice()
mockBlueprint.EXPECT().HasCommand("primary").Return(false).Once()

sql := s.grammar.CompileAdd(mockBlueprint, &contractsdriver.Command{
Expand All @@ -56,7 +57,8 @@ func (s *GrammarSuite) TestCompileChange() {
mockColumn.EXPECT().GetDefault().Return("goravel").Twice()
mockColumn.EXPECT().GetNullable().Return(false).Once()
mockColumn.EXPECT().GetLength().Return(1).Once()
mockColumn.EXPECT().IsChange().Return(true).Times(3)
mockColumn.EXPECT().IsChange().Return(true).Times(4)
mockColumn.EXPECT().IsSetGeneratedAs().Return(false).Times(3)
mockColumn.EXPECT().GetAutoIncrement().Return(false).Once()

sql := s.grammar.CompileChange(mockBlueprint, &contractsdriver.Command{
Expand Down Expand Up @@ -159,7 +161,8 @@ func (s *GrammarSuite) TestCompileCreate() {
mockColumn1.EXPECT().GetAutoIncrement().Return(true).Once()
// postgres.go::ModifyNullable
mockColumn1.EXPECT().GetNullable().Return(false).Once()
mockColumn1.EXPECT().IsChange().Return(false).Times(3)
mockColumn1.EXPECT().IsChange().Return(false).Times(5)
mockColumn1.EXPECT().IsSetGeneratedAs().Return(false).Twice()

// utils.go::getColumns
mockColumn2.EXPECT().GetName().Return("name").Once()
Expand All @@ -174,7 +177,8 @@ func (s *GrammarSuite) TestCompileCreate() {
mockColumn2.EXPECT().GetType().Return("string").Once()
// postgres.go::ModifyNullable
mockColumn2.EXPECT().GetNullable().Return(true).Once()
mockColumn2.EXPECT().IsChange().Return(false).Times(3)
mockColumn2.EXPECT().IsChange().Return(false).Times(4)
mockColumn2.EXPECT().IsSetGeneratedAs().Return(false).Twice()

s.Equal(`create table "goravel_users" ("id" serial primary key not null, "name" varchar(100) null)`,
s.grammar.CompileCreate(mockBlueprint))
Expand Down Expand Up @@ -415,14 +419,16 @@ func (s *GrammarSuite) TestGetColumns() {
mockColumn1.EXPECT().GetDefault().Return(nil).Once()
mockColumn1.EXPECT().GetNullable().Return(false).Once()
mockColumn1.EXPECT().GetAutoIncrement().Return(true).Twice()
mockColumn1.EXPECT().IsChange().Return(false).Times(3)
mockColumn1.EXPECT().IsChange().Return(false).Times(5)
mockColumn1.EXPECT().IsSetGeneratedAs().Return(false).Twice()

mockColumn2.EXPECT().GetName().Return("name").Once()
mockColumn2.EXPECT().GetType().Return("string").Twice()
mockColumn2.EXPECT().GetDefault().Return("goravel").Twice()
mockColumn2.EXPECT().GetNullable().Return(true).Once()
mockColumn2.EXPECT().GetLength().Return(10).Once()
mockColumn2.EXPECT().IsChange().Return(false).Times(3)
mockColumn2.EXPECT().IsChange().Return(false).Times(4)
mockColumn2.EXPECT().IsSetGeneratedAs().Return(false).Twice()

s.Equal([]string{"\"id\" serial primary key not null", "\"name\" varchar(10) default 'goravel' null"}, s.grammar.getColumns(mockBlueprint))
}
Expand Down Expand Up @@ -475,6 +481,7 @@ func (s *GrammarSuite) TestModifyDefault() {
mockColumn.EXPECT().IsChange().Return(true).Once()
mockColumn.EXPECT().GetAutoIncrement().Return(false).Once()
mockColumn.EXPECT().GetDefault().Return(nil).Once()
mockColumn.EXPECT().IsSetGeneratedAs().Return(false).Once()
},
expectSql: " drop default",
},
Expand All @@ -492,6 +499,7 @@ func (s *GrammarSuite) TestModifyDefault() {
mockColumn.EXPECT().IsChange().Return(true).Once()
mockColumn.EXPECT().GetAutoIncrement().Return(false).Once()
mockColumn.EXPECT().GetDefault().Return("goravel").Twice()
mockColumn.EXPECT().IsSetGeneratedAs().Return(false).Once()
},
expectSql: " set default 'goravel'",
},
Expand All @@ -511,6 +519,90 @@ func (s *GrammarSuite) TestModifyDefault() {
}
}

func (s *GrammarSuite) TestModifyGeneratedAs() {
var (
mockBlueprint *mocksdriver.Blueprint
mockColumn *mocksdriver.ColumnDefinition
)

tests := []struct {
name string
setup func()
expectSql []string
}{
{
name: "generated by default",
setup: func() {
mockColumn.EXPECT().IsChange().Return(false).Twice()
mockColumn.EXPECT().IsSetGeneratedAs().Return(true).Once()
mockColumn.EXPECT().IsAlways().Return(false).Once()
mockColumn.EXPECT().GetGeneratedAs().Return("").Once()
},
expectSql: []string{" generated by default as identity"},
},
{
name: "generated always",
setup: func() {
mockColumn.EXPECT().IsChange().Return(false).Twice()
mockColumn.EXPECT().IsSetGeneratedAs().Return(true).Once()
mockColumn.EXPECT().IsAlways().Return(true).Once()
mockColumn.EXPECT().GetGeneratedAs().Return("").Once()
},
expectSql: []string{" generated always as identity"},
},
{
name: "generated by default with expression",
setup: func() {
mockColumn.EXPECT().IsChange().Return(false).Twice()
mockColumn.EXPECT().IsSetGeneratedAs().Return(true).Once()
mockColumn.EXPECT().IsAlways().Return(false).Once()
mockColumn.EXPECT().GetGeneratedAs().Return("START WITH 1000 INCREMENT BY 5").Once()
},
expectSql: []string{" generated by default as identity (START WITH 1000 INCREMENT BY 5)"},
},
{
name: "generated always with expression",
setup: func() {
mockColumn.EXPECT().IsChange().Return(false).Twice()
mockColumn.EXPECT().IsSetGeneratedAs().Return(true).Once()
mockColumn.EXPECT().IsAlways().Return(true).Once()
mockColumn.EXPECT().GetGeneratedAs().Return("START WITH 1000 INCREMENT BY 5").Once()
},
expectSql: []string{" generated always as identity (START WITH 1000 INCREMENT BY 5)"},
},
{
name: "generated always with expression for change",
setup: func() {
mockColumn.EXPECT().IsChange().Return(true).Twice()
mockColumn.EXPECT().GetAutoIncrement().Return(false).Once()
mockColumn.EXPECT().IsSetGeneratedAs().Return(true).Twice()
mockColumn.EXPECT().IsAlways().Return(true).Once()
mockColumn.EXPECT().GetGeneratedAs().Return("START WITH 1000 INCREMENT BY 5").Once()
},
expectSql: []string{" drop identity if exists", " add generated always as identity (START WITH 1000 INCREMENT BY 5)"},
Comment thread
hwbrzzl marked this conversation as resolved.
},
}

for _, test := range tests {
s.Run(test.name, func() {
mockBlueprint = mocksdriver.NewBlueprint(s.T())
mockColumn = mocksdriver.NewColumnDefinition(s.T())

test.setup()

var actualSql []string
if sql := s.grammar.ModifyGeneratedAsForChange(mockBlueprint, mockColumn); len(sql) > 0 {
actualSql = append(actualSql, sql)
}
if sql := s.grammar.ModifyGeneratedAs(mockBlueprint, mockColumn); len(sql) > 0 {
actualSql = append(actualSql, sql)
}

s.Equal(test.expectSql, actualSql)
})
}
}

func (s *GrammarSuite) TestModifyNullable() {
var (
mockBlueprint *mocksdriver.Blueprint
Expand Down Expand Up @@ -594,6 +686,8 @@ func (s *GrammarSuite) TestTableComment() {
func (s *GrammarSuite) TestTypeBigInteger() {
mockColumn1 := mocksdriver.NewColumnDefinition(s.T())
mockColumn1.EXPECT().GetAutoIncrement().Return(true).Once()
mockColumn1.EXPECT().IsChange().Return(false).Once()
mockColumn1.EXPECT().IsSetGeneratedAs().Return(false).Once()

s.Equal("bigserial", s.grammar.TypeBigInteger(mockColumn1))

Expand Down Expand Up @@ -633,6 +727,8 @@ func (s *GrammarSuite) TestTypeFloat() {
func (s *GrammarSuite) TestTypeInteger() {
mockColumn1 := mocksdriver.NewColumnDefinition(s.T())
mockColumn1.EXPECT().GetAutoIncrement().Return(true).Once()
mockColumn1.EXPECT().IsChange().Return(false).Once()
mockColumn1.EXPECT().IsSetGeneratedAs().Return(false).Once()

s.Equal("serial", s.grammar.TypeInteger(mockColumn1))

Expand Down