Repository: ariga/atlas
Pull request #3164 (2024-09-29 15:17:50)

sql/sqlite: allow setting user-defined types


Patch:
diff --git a/sql/sqlite/convert.go b/sql/sqlite/convert.go
index 55ef8cb0..a6fa876c 100644
--- a/sql/sqlite/convert.go
+++ b/sql/sqlite/convert.go
@@ -41,6 +41,8 @@ func FormatType(t schema.Type) (string, error) {
 		f = strings.ToLower(t.T)
 	case *schema.UUIDType:
 		f = strings.ToLower(t.T)
+	case *UserDefinedType:
+		f = t.T
 	case *schema.UnsupportedType:
 		return "", fmt.Errorf("sqlite: unsupported type: %q", t.T)
 	default:
@@ -102,6 +104,6 @@ func ParseType(c string) (schema.Type, error) {
 	case "uuid":
 		return &schema.UUIDType{T: t}, nil
 	default:
-		return &schema.UnsupportedType{T: t}, nil
+		return &UserDefinedType{T: c}, nil
 	}
 }
diff --git a/sql/sqlite/diff.go b/sql/sqlite/diff.go
index 60628ca4..c728b4bb 100644
--- a/sql/sqlite/diff.go
+++ b/sql/sqlite/diff.go
@@ -91,6 +91,10 @@ func (d *diff) typeChanged(from, to *schema.Column) (bool, error) {
 	if fromT == nil || toT == nil {
 		return false, fmt.Errorf("sqlite: missing type information for column %q", from.Name)
 	}
+	if u1, ok := fromT.(*UserDefinedType); ok {
+		u2, ok := toT.(*UserDefinedType)
+		return !ok || u1.T != u2.T, nil
+	}
 	// Types are mismatched if they do not have the same "type affinity".
 	return reflect.TypeOf(fromT) != reflect.TypeOf(toT), nil
 }
diff --git a/sql/sqlite/inspect.go b/sql/sqlite/inspect.go
index 4677d32f..2b56d7bb 100644
--- a/sql/sqlite/inspect.go
+++ b/sql/sqlite/inspect.go
@@ -515,6 +515,12 @@ type (
 	//
 	// Deprecated: Use schema.UUIDType instead.
 	UUIDType = schema.UUIDType
+
+	// UserDefinedType defines a user-defined type attribute.
+	UserDefinedType struct {
+		schema.Type
+		T string
+	}
 )
 
 func columnParts(t string) []string {


Test patch:
diff --git a/internal/integration/testdata/sqlite/column-user-defined.txt b/internal/integration/testdata/sqlite/column-user-defined.txt
new file mode 100644
index 00000000..fcf96fe9
--- /dev/null
+++ b/internal/integration/testdata/sqlite/column-user-defined.txt
@@ -0,0 +1,54 @@
+# Initial changes.
+atlas schema apply --url URL --dev-url DEV_URL --to file://schema.v1.hcl --auto-approve
+atlas schema apply --url URL --dev-url DEV_URL --to file://schema.v1.hcl --auto-approve
+stdout 'Schema is synced, no changes to be made'
+atlas schema inspect --url URL > got
+cmp schema.v1.hcl.inspected got
+
+# Changing user defined type.
+atlas schema apply --url URL --dev-url DEV_URL --to file://schema.v2.hcl --auto-approve
+atlas schema apply --url URL --dev-url DEV_URL --to file://schema.v2.hcl --auto-approve
+stdout 'Schema is synced, no changes to be made'
+atlas schema inspect --url URL > got
+cmp schema.v2.hcl.inspected got
+
+-- schema.v1.hcl --
+table "t" {
+  schema = schema.main
+  column "c" {
+    null = true
+    type = sql("USER_DEFINED")
+  }
+}
+schema "main" {
+}
+-- schema.v1.hcl.inspected --
+table "t" {
+  schema = schema.main
+  column "c" {
+    null = true
+    type = sql("USER_DEFINED")
+  }
+}
+schema "main" {
+}
+-- schema.v2.hcl --
+table "t" {
+  schema = schema.main
+  column "c" {
+    null = true
+    type = sql("USER_TYPE")
+  }
+}
+schema "main" {
+}
+-- schema.v2.hcl.inspected --
+table "t" {
+  schema = schema.main
+  column "c" {
+    null = true
+    type = sql("USER_TYPE")
+  }
+}
+schema "main" {
+}
\ No newline at end of file
diff --git a/sql/sqlite/sqlspec_test.go b/sql/sqlite/sqlspec_test.go
index 8f83dfb5..5a97fc85 100644
--- a/sql/sqlite/sqlspec_test.go
+++ b/sql/sqlite/sqlspec_test.go
@@ -344,7 +344,7 @@ func TestTypes(t *testing.T) {
 		},
 		{
 			typeExpr: `sql("custom")`,
-			expected: &schema.UnsupportedType{T: "custom"},
+			expected: &UserDefinedType{T: "custom"},
 		},
 		{
 			typeExpr: "tinyint(10)",