Repository: ariga/atlas
Pull request #480 (2022-01-24 16:18:43)

internal/integration: test foreign-key action modification


Patch:
diff --git a/internal/integration/go.sum b/internal/integration/go.sum
index b0fb2e6d..87b9876b 100644
--- a/internal/integration/go.sum
+++ b/internal/integration/go.sum
@@ -384,8 +384,6 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
-github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
 github.com/rogpeppe/go-internal v1.8.2-0.20220112175052-f3cb5c2c6412 h1:BVgfta5l+NeAx6l597tEbF2TkiVi+Mw+2vxJjwSfyRU=
 github.com/rogpeppe/go-internal v1.8.2-0.20220112175052-f3cb5c2c6412/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
diff --git a/sql/mysql/sqlspec.go b/sql/mysql/sqlspec.go
index eef8db23..08fd66c0 100644
--- a/sql/mysql/sqlspec.go
+++ b/sql/mysql/sqlspec.go
@@ -272,11 +272,11 @@ var TypeRegistry = specutil.NewRegistry(
 		specutil.TypeSpec(TypeFloat, &schemaspec.TypeAttr{Name: "precision", Kind: reflect.Int, Required: false}, &schemaspec.TypeAttr{Name: "scale", Kind: reflect.Int, Required: false}),
 		specutil.TypeSpec(TypeDouble, &schemaspec.TypeAttr{Name: "precision", Kind: reflect.Int, Required: false}, &schemaspec.TypeAttr{Name: "scale", Kind: reflect.Int, Required: false}),
 		specutil.TypeSpec(TypeReal, &schemaspec.TypeAttr{Name: "precision", Kind: reflect.Int, Required: false}, &schemaspec.TypeAttr{Name: "scale", Kind: reflect.Int, Required: false}),
-		specutil.TypeSpec(TypeTimestamp),
-		specutil.TypeSpec(TypeDate),
-		specutil.TypeSpec(TypeTime),
-		specutil.TypeSpec(TypeDateTime),
-		specutil.TypeSpec(TypeYear),
+		specutil.TypeSpec(TypeTimestamp, &schemaspec.TypeAttr{Name: "precision", Kind: reflect.Int, Required: false}),
+		specutil.TypeSpec(TypeDate, &schemaspec.TypeAttr{Name: "precision", Kind: reflect.Int, Required: false}),
+		specutil.TypeSpec(TypeTime, &schemaspec.TypeAttr{Name: "precision", Kind: reflect.Int, Required: false}),
+		specutil.TypeSpec(TypeDateTime, &schemaspec.TypeAttr{Name: "precision", Kind: reflect.Int, Required: false}),
+		specutil.TypeSpec(TypeYear, &schemaspec.TypeAttr{Name: "precision", Kind: reflect.Int, Required: false}),
 		specutil.TypeSpec(TypeVarchar, specutil.SizeTypeAttr(true)),
 		specutil.TypeSpec(TypeChar, specutil.SizeTypeAttr(false)),
 		specutil.TypeSpec(TypeVarBinary, specutil.SizeTypeAttr(false)),


Test patch:
diff --git a/internal/integration/integration_test.go b/internal/integration/integration_test.go
index 64fa948b..9cc86d30 100644
--- a/internal/integration/integration_test.go
+++ b/internal/integration/integration_test.go
@@ -382,6 +382,15 @@ func TestMySQLScript(t *testing.T) {
 						if !re.MatchString(err.Error()) {
 							t.Fatalf("mismatched errors: %v != %s", err, args[1])
 						}
+					// Apply passed. Make sure there is no drift.
+					case !neg:
+						current, err := t.drv.InspectSchema(context.Background(), desired.Name, nil)
+						ts.Check(err)
+						changes, err := t.drv.SchemaDiff(current, &desired)
+						ts.Check(err)
+						if len(changes) > 0 {
+							ts.Fatalf("unexpected schema drift: %v", changes)
+						}
 					}
 				},
 				"exist": func(ts *testscript.TestScript, neg bool, args []string) {
diff --git a/internal/integration/testdata/mysql/modify-foreign-key-action.txt b/internal/integration/testdata/mysql/modify-foreign-key-action.txt
new file mode 100644
index 00000000..84cd3068
--- /dev/null
+++ b/internal/integration/testdata/mysql/modify-foreign-key-action.txt
@@ -0,0 +1,133 @@
+# Each test runs on a clean database.
+
+# Apply schema "1.hcl" on fresh database.
+apply 1.hcl
+cmpshow users posts 1.sql
+
+apply 2.hcl
+cmpshow users posts 2.sql
+
+# Below files represent HCL and SQL. File names defined their index in
+# execution order. 1.hcl is executed first, 2.hcl executed second, etc.
+-- 1.hcl --
+schema "$db" {
+    charset = "$charset"
+    collation = "$collate"
+}
+
+table "users" {
+    schema = schema.$db
+    column "id" {
+        type = int
+    }
+    primary_key {
+        columns = [table.users.column.id]
+    }
+}
+
+table "posts" {
+    schema = schema.$db
+    column "id" {
+        type = int
+    }
+    column "author_id" {
+        type = int
+        null = true
+    }
+    primary_key {
+        columns = [table.posts.column.id]
+    }
+    foreign_key "owner_id" {
+    	columns = [table.posts.column.author_id]
+    	ref_columns = [table.users.column.id]
+    	on_update = "SET NULL"
+    }
+}
+
+-- 1.sql --
+CREATE TABLE `users` (
+  `id` int(11) NOT NULL,
+  PRIMARY KEY (`id`)
+)
+CREATE TABLE `posts` (
+  `id` int(11) NOT NULL,
+  `author_id` int(11) DEFAULT NULL,
+  PRIMARY KEY (`id`),
+  KEY `owner_id` (`author_id`),
+  CONSTRAINT `owner_id` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`) ON UPDATE SET NULL
+)
+
+-- 8/1.sql --
+CREATE TABLE `users` (
+  `id` int NOT NULL,
+  PRIMARY KEY (`id`)
+)
+CREATE TABLE `posts` (
+  `id` int NOT NULL,
+  `author_id` int DEFAULT NULL,
+  PRIMARY KEY (`id`),
+  KEY `owner_id` (`author_id`),
+  CONSTRAINT `owner_id` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`) ON UPDATE SET NULL
+)
+
+-- 2.hcl --
+schema "$db" {
+    charset = "$charset"
+    collation = "$collate"
+}
+
+table "users" {
+    schema = schema.$db
+    column "id" {
+        type = int
+    }
+    primary_key {
+        columns = [table.users.column.id]
+    }
+}
+
+table "posts" {
+    schema = schema.$db
+    column "id" {
+        type = int
+    }
+    column "author_id" {
+        type = int
+        null = true
+    }
+    primary_key {
+        columns = [table.posts.column.id]
+    }
+    foreign_key "owner_id" {
+    	columns = [table.posts.column.author_id]
+    	ref_columns = [table.users.column.id]
+    	on_update = "NO ACTION"
+    	on_delete = "CASCADE"
+    }
+}
+
+-- 2.sql --
+CREATE TABLE `users` (
+  `id` int(11) NOT NULL,
+  PRIMARY KEY (`id`)
+)
+CREATE TABLE `posts` (
+  `id` int(11) NOT NULL,
+  `author_id` int(11) DEFAULT NULL,
+  PRIMARY KEY (`id`),
+  KEY `owner_id` (`author_id`),
+  CONSTRAINT `owner_id` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
+)
+
+-- 8/2.sql --
+CREATE TABLE `users` (
+  `id` int NOT NULL,
+  PRIMARY KEY (`id`)
+)
+CREATE TABLE `posts` (
+  `id` int NOT NULL,
+  `author_id` int DEFAULT NULL,
+  PRIMARY KEY (`id`),
+  KEY `owner_id` (`author_id`),
+  CONSTRAINT `owner_id` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
+)
\ No newline at end of file
diff --git a/sql/mysql/sqlspec_test.go b/sql/mysql/sqlspec_test.go
index 7a6af0ca..b5e16f4c 100644
--- a/sql/mysql/sqlspec_test.go
+++ b/sql/mysql/sqlspec_test.go
@@ -441,6 +441,54 @@ schema "test" {
 	require.EqualValues(t, expected, string(buf))
 }
 
+func TestMarshalSpec_TimePrecision(t *testing.T) {
+	s := schema.New("test").
+		AddTables(
+			schema.NewTable("times").
+				AddColumns(
+					schema.NewTimeColumn("tTimeDef", TypeTime),
+					schema.NewTimeColumn("tTime", TypeTime, schema.TimePrecision(1)),
+					schema.NewTimeColumn("tDatetime", TypeDateTime, schema.TimePrecision(2)),
+					schema.NewTimeColumn("tTimestamp", TypeTimestamp, schema.TimePrecision(3)),
+					schema.NewTimeColumn("tDate", TypeDate, schema.TimePrecision(2)),
+					schema.NewTimeColumn("tYear", TypeYear, schema.TimePrecision(2)),
+				),
+		)
+	buf, err := MarshalSpec(s, hclState)
+	require.NoError(t, err)
+	const expected = `table "times" {
+  schema = schema.test
+  column "tTimeDef" {
+    null = false
+    type = time
+  }
+  column "tTime" {
+    null = false
+    type = time(1)
+  }
+  column "tDatetime" {
+    null = false
+    type = datetime(2)
+  }
+  column "tTimestamp" {
+    null = false
+    type = timestamp(3)
+  }
+  column "tDate" {
+    null = false
+    type = date(2)
+  }
+  column "tYear" {
+    null = false
+    type = year(2)
+  }
+}
+schema "test" {
+}
+`
+	require.EqualValues(t, expected, string(buf))
+}
+
 func TestTypes(t *testing.T) {
 	tests := []struct {
 		typeExpr  string
@@ -600,22 +648,42 @@ func TestTypes(t *testing.T) {
 			typeExpr: "timestamp",
 			expected: &schema.TimeType{T: TypeTimestamp},
 		},
+		{
+			typeExpr: "timestamp(6)",
+			expected: &schema.TimeType{T: TypeTimestamp, Precision: 6},
+		},
 		{
 			typeExpr: "date",
 			expected: &schema.TimeType{T: TypeDate},
 		},
+		{
+			typeExpr: "date(2)",
+			expected: &schema.TimeType{T: TypeDate, Precision: 2},
+		},
 		{
 			typeExpr: "time",
 			expected: &schema.TimeType{T: TypeTime},
 		},
+		{
+			typeExpr: "time(6)",
+			expected: &schema.TimeType{T: TypeTime, Precision: 6},
+		},
 		{
 			typeExpr: "datetime",
 			expected: &schema.TimeType{T: TypeDateTime},
 		},
+		{
+			typeExpr: "datetime(6)",
+			expected: &schema.TimeType{T: TypeDateTime, Precision: 6},
+		},
 		{
 			typeExpr: "year",
 			expected: &schema.TimeType{T: TypeYear},
 		},
+		{
+			typeExpr: "year(2)",
+			expected: &schema.TimeType{T: TypeYear, Precision: 2},
+		},
 		{
 			typeExpr: "varchar(10)",
 			expected: &schema.StringType{T: TypeVarchar, Size: 10},