@@ -49,13 +49,24 @@ func generateCreateTypesSQL(w *SQLWriter, types []*ir.Type, targetSchema string)
4949// generateModifyTypesSQL generates ALTER TYPE statements
5050func generateModifyTypesSQL (w * SQLWriter , diffs []* TypeDiff , targetSchema string ) {
5151 for _ , diff := range diffs {
52- // Only ENUM types can be modified by adding values
53- if diff .Old .Kind == ir .TypeKindEnum && diff .New .Kind == ir .TypeKindEnum {
54- // Generate ALTER TYPE ... ADD VALUE statements for new enum values
55- alterStatements := generateAlterTypeEnumStatements (diff .Old , diff .New , targetSchema )
56- for _ , stmt := range alterStatements {
57- w .WriteDDLSeparator ()
58- w .WriteString (stmt ) // No comments for diff scenarios
52+ switch diff .Old .Kind {
53+ case ir .TypeKindEnum :
54+ // ENUM types can be modified by adding values
55+ if diff .New .Kind == ir .TypeKindEnum {
56+ alterStatements := generateAlterTypeEnumStatements (diff .Old , diff .New , targetSchema )
57+ for _ , stmt := range alterStatements {
58+ w .WriteDDLSeparator ()
59+ w .WriteString (stmt ) // No comments for diff scenarios
60+ }
61+ }
62+ case ir .TypeKindDomain :
63+ // Domain types can be modified with ALTER DOMAIN
64+ if diff .New .Kind == ir .TypeKindDomain {
65+ alterStatements := generateAlterDomainStatements (diff .Old , diff .New , targetSchema )
66+ for _ , stmt := range alterStatements {
67+ w .WriteDDLSeparator ()
68+ w .WriteString (stmt + "\n " )
69+ }
5970 }
6071 }
6172 }
@@ -73,8 +84,18 @@ func generateDropTypesSQL(w *SQLWriter, types []*ir.Type, targetSchema string) {
7384 for _ , typeObj := range sortedTypes {
7485 w .WriteDDLSeparator ()
7586 typeName := qualifyEntityName (typeObj .Schema , typeObj .Name , targetSchema )
76- sql := fmt .Sprintf ("DROP TYPE IF EXISTS %s CASCADE;" , typeName )
77- w .WriteStatementWithComment ("TYPE" , typeObj .Name , typeObj .Schema , "" , sql , targetSchema )
87+
88+ var sql string
89+ var objectType string
90+ if typeObj .Kind == ir .TypeKindDomain {
91+ sql = fmt .Sprintf ("DROP DOMAIN IF EXISTS %s RESTRICT;" , typeName )
92+ objectType = "DOMAIN"
93+ } else {
94+ sql = fmt .Sprintf ("DROP TYPE IF EXISTS %s RESTRICT;" , typeName )
95+ objectType = "TYPE"
96+ }
97+
98+ w .WriteStatementWithComment (objectType , typeObj .Name , typeObj .Schema , "" , sql , targetSchema )
7899 }
79100}
80101
@@ -112,6 +133,80 @@ func generateAlterTypeEnumStatements(oldType, newType *ir.Type, targetSchema str
112133 return statements
113134}
114135
136+ // generateAlterDomainStatements generates ALTER DOMAIN statements for domain changes
137+ func generateAlterDomainStatements (oldDomain , newDomain * ir.Type , targetSchema string ) []string {
138+ var statements []string
139+ domainName := qualifyEntityName (newDomain .Schema , newDomain .Name , targetSchema )
140+
141+ // Check if default value changed
142+ if oldDomain .Default != newDomain .Default {
143+ if newDomain .Default == "" {
144+ statements = append (statements , fmt .Sprintf ("ALTER DOMAIN %s DROP DEFAULT;" , domainName ))
145+ } else {
146+ statements = append (statements , fmt .Sprintf ("ALTER DOMAIN %s SET DEFAULT %s;" , domainName , newDomain .Default ))
147+ }
148+ }
149+
150+ // Check if NOT NULL changed
151+ if oldDomain .NotNull != newDomain .NotNull {
152+ if newDomain .NotNull {
153+ statements = append (statements , fmt .Sprintf ("ALTER DOMAIN %s SET NOT NULL;" , domainName ))
154+ } else {
155+ statements = append (statements , fmt .Sprintf ("ALTER DOMAIN %s DROP NOT NULL;" , domainName ))
156+ }
157+ }
158+
159+ // Check constraints changes
160+ // Create maps for easier comparison
161+ oldConstraints := make (map [string ]* ir.DomainConstraint )
162+ for _ , c := range oldDomain .Constraints {
163+ key := c .Name
164+ if key == "" {
165+ key = c .Definition
166+ }
167+ oldConstraints [key ] = c
168+ }
169+
170+ newConstraints := make (map [string ]* ir.DomainConstraint )
171+ for _ , c := range newDomain .Constraints {
172+ key := c .Name
173+ if key == "" {
174+ key = c .Definition
175+ }
176+ newConstraints [key ] = c
177+ }
178+
179+ // Drop removed constraints
180+ for key , oldConstraint := range oldConstraints {
181+ if newConstraint , exists := newConstraints [key ]; ! exists {
182+ // Constraint was removed
183+ if oldConstraint .Name != "" {
184+ statements = append (statements , fmt .Sprintf ("ALTER DOMAIN %s DROP CONSTRAINT %s;" , domainName , oldConstraint .Name ))
185+ }
186+ // Note: unnamed constraints cannot be dropped individually
187+ } else if oldConstraint .Name != "" && oldConstraint .Definition != newConstraint .Definition {
188+ // Constraint exists but definition changed - need to drop and recreate
189+ statements = append (statements , fmt .Sprintf ("ALTER DOMAIN %s DROP CONSTRAINT %s;" , domainName , oldConstraint .Name ))
190+ }
191+ }
192+
193+ // Add new constraints
194+ for key , newConstraint := range newConstraints {
195+ oldConstraint , exists := oldConstraints [key ]
196+ if ! exists || (exists && oldConstraint .Definition != newConstraint .Definition ) {
197+ // Either new constraint or definition changed
198+ constraintDef := newConstraint .Definition
199+ if newConstraint .Name != "" {
200+ statements = append (statements , fmt .Sprintf ("ALTER DOMAIN %s ADD CONSTRAINT %s %s;" , domainName , newConstraint .Name , constraintDef ))
201+ } else {
202+ statements = append (statements , fmt .Sprintf ("ALTER DOMAIN %s ADD %s;" , domainName , constraintDef ))
203+ }
204+ }
205+ }
206+
207+ return statements
208+ }
209+
115210// generateTypeSQL generates CREATE TYPE statement
116211func generateTypeSQL (typeObj * ir.Type , targetSchema string ) string {
117212 // Only include type name without schema if it's in the target schema
@@ -144,22 +239,35 @@ func generateTypeSQL(typeObj *ir.Type, targetSchema string) string {
144239 }
145240 return fmt .Sprintf ("CREATE TYPE %s AS (%s);" , typeName , strings .Join (attributes , ", " ))
146241 case ir .TypeKindDomain :
147- stmt := fmt .Sprintf ("CREATE DOMAIN %s AS %s" , typeName , typeObj .BaseType )
242+ // Use multi-line format for better readability if there are constraints
243+ hasConstraints := len (typeObj .Constraints ) > 0 || typeObj .NotNull || typeObj .Default != ""
244+
245+ if ! hasConstraints {
246+ return fmt .Sprintf ("CREATE DOMAIN %s AS %s;" , typeName , typeObj .BaseType )
247+ }
248+
249+ // Multi-line format
250+ lines := []string {fmt .Sprintf ("CREATE DOMAIN %s AS %s" , typeName , typeObj .BaseType )}
251+
148252 if typeObj .Default != "" {
149- stmt += fmt .Sprintf (" DEFAULT %s" , typeObj .Default )
253+ lines = append ( lines , fmt .Sprintf (" DEFAULT %s" , typeObj .Default ) )
150254 }
151255 if typeObj .NotNull {
152- stmt += " NOT NULL"
256+ lines = append ( lines , " NOT NULL")
153257 }
258+
154259 // Add domain constraints (CHECK constraints)
260+ // Normalize VALUE to uppercase for consistency
155261 for _ , constraint := range typeObj .Constraints {
262+ constraintDef := constraint .Definition
156263 if constraint .Name != "" {
157- stmt += fmt .Sprintf (" CONSTRAINT %s %s" , constraint .Name , constraint . Definition )
264+ lines = append ( lines , fmt .Sprintf (" CONSTRAINT %s %s" , constraint .Name , constraintDef ) )
158265 } else {
159- stmt += fmt .Sprintf (" %s" , constraint . Definition )
266+ lines = append ( lines , fmt .Sprintf (" %s" , constraintDef ) )
160267 }
161268 }
162- return stmt + ";"
269+
270+ return strings .Join (lines , "\n " ) + ";"
163271 default :
164272 return fmt .Sprintf ("CREATE TYPE %s;" , typeName )
165273 }
0 commit comments