Skip to content

Commit 5406e41

Browse files
authoredMar 10, 2025··
fix: cover more constraint syntax (#198)
SQLite stores the DDL "as-is" in `sqlite_master`. This new regex covers a broader range of valid syntax for constraints.
1 parent 02b8e06 commit 5406e41

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed
 

‎ddlmod.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,12 @@ func (d *ddl) renameTable(dst, src string) error {
209209
return nil
210210
}
211211

212+
func compileConstraintRegexp(name string) *regexp.Regexp {
213+
return regexp.MustCompile("^(?i:CONSTRAINT)\\s+[\"`]?" + regexp.QuoteMeta(name) + "[\"`\\s]")
214+
}
215+
212216
func (d *ddl) addConstraint(name string, sql string) {
213-
reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]")
217+
reg := compileConstraintRegexp(name)
214218

215219
for i := 0; i < len(d.fields); i++ {
216220
if reg.MatchString(d.fields[i]) {
@@ -223,7 +227,7 @@ func (d *ddl) addConstraint(name string, sql string) {
223227
}
224228

225229
func (d *ddl) removeConstraint(name string) bool {
226-
reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]")
230+
reg := compileConstraintRegexp(name)
227231

228232
for i := 0; i < len(d.fields); i++ {
229233
if reg.MatchString(d.fields[i]) {
@@ -235,7 +239,7 @@ func (d *ddl) removeConstraint(name string) bool {
235239
}
236240

237241
func (d *ddl) hasConstraint(name string) bool {
238-
reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]")
242+
reg := compileConstraintRegexp(name)
239243

240244
for _, f := range d.fields {
241245
if reg.MatchString(f) {

‎ddlmod_test.go

+35
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,41 @@ func TestRemoveConstraint(t *testing.T) {
313313
success: true,
314314
expect: []string{"`id` integer NOT NULL"},
315315
},
316+
{
317+
name: "lowercase",
318+
fields: []string{"`id` integer NOT NULL", "constraint `fk_users_notes` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`))"},
319+
cName: "fk_users_notes",
320+
success: true,
321+
expect: []string{"`id` integer NOT NULL"},
322+
},
323+
{
324+
name: "mixed_case",
325+
fields: []string{"`id` integer NOT NULL", "cOnsTraiNT `fk_users_notes` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`))"},
326+
cName: "fk_users_notes",
327+
success: true,
328+
expect: []string{"`id` integer NOT NULL"},
329+
},
330+
{
331+
name: "newline",
332+
fields: []string{"`id` integer NOT NULL", "CONSTRAINT `fk_users_notes`\nFOREIGN KEY (`user_id`) REFERENCES `users`(`id`))"},
333+
cName: "fk_users_notes",
334+
success: true,
335+
expect: []string{"`id` integer NOT NULL"},
336+
},
337+
{
338+
name: "lots_of_newlines",
339+
fields: []string{"`id` integer NOT NULL", "constraint \n fk_users_notes \n FOREIGN KEY (`user_id`) REFERENCES `users`(`id`))"},
340+
cName: "fk_users_notes",
341+
success: true,
342+
expect: []string{"`id` integer NOT NULL"},
343+
},
344+
{
345+
name: "no_backtick",
346+
fields: []string{"`id` integer NOT NULL", "CONSTRAINT fk_users_notes FOREIGN KEY (`user_id`) REFERENCES `users`(`id`))"},
347+
cName: "fk_users_notes",
348+
success: true,
349+
expect: []string{"`id` integer NOT NULL"},
350+
},
316351
{
317352
name: "check",
318353
fields: []string{"CONSTRAINT `name_checker` CHECK (`name` <> 'thetadev')", "`id` integer NOT NULL"},

0 commit comments

Comments
 (0)
Please sign in to comment.