From b1f3b1075b07c72fcfa6dce9a4b25fe4ba785ab7 Mon Sep 17 00:00:00 2001 From: Justin McIntyre Date: Wed, 4 Mar 2026 10:49:04 -0400 Subject: [PATCH 1/2] fix: strip quotes from type names in view dependency detection When a function returns a quoted type like SETOF public."ViewName", the extractBaseTypeName function was not stripping the double quotes. This caused the lookup in functionReferencesNewView to fail because the view lookup map stores unquoted names (e.g., public.viewname). As a result, functions with quoted return types were not detected as having view dependencies, causing them to be created before the views they depend on, leading to "type does not exist" errors. Co-Authored-By: Claude Opus 4.5 --- internal/diff/diff.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/diff/diff.go b/internal/diff/diff.go index 48f8b5e9..5ae3a1f6 100644 --- a/internal/diff/diff.go +++ b/internal/diff/diff.go @@ -1929,7 +1929,7 @@ func functionReferencesNewView(fn *ir.Function, newViews map[string]struct{}) bo } // extractBaseTypeName extracts the base type name from a type expression, -// stripping SETOF prefix and array notation. +// stripping SETOF prefix, array notation, and double quotes from identifiers. func extractBaseTypeName(typeExpr string) string { t := strings.TrimSpace(typeExpr) // Strip SETOF prefix (case-insensitive) @@ -1940,6 +1940,8 @@ func extractBaseTypeName(typeExpr string) string { for len(t) > 2 && t[len(t)-2:] == "[]" { t = t[:len(t)-2] } + // Strip double quotes from identifiers (e.g., public."ViewName" -> public.ViewName) + t = strings.ReplaceAll(t, "\"", "") return t } From 57613f4149569fbb8187b72d403450560ee3afa1 Mon Sep 17 00:00:00 2001 From: Justin McIntyre Date: Thu, 12 Mar 2026 15:35:16 -0300 Subject: [PATCH 2/2] test: add unit tests for extractBaseTypeName Add tests for the extractBaseTypeName function to verify correct handling of quoted identifiers in type expressions. Tests cover: - Simple types - SETOF prefix with schema-qualified types - Quoted type names (e.g., SETOF public."ViewName") - Quoted schema and type names - Array notation - Combined cases (SETOF + quoted + array) Co-Authored-By: Claude Opus 4.5 --- internal/diff/type_extract_test.go | 61 ++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 internal/diff/type_extract_test.go diff --git a/internal/diff/type_extract_test.go b/internal/diff/type_extract_test.go new file mode 100644 index 00000000..c9a7a568 --- /dev/null +++ b/internal/diff/type_extract_test.go @@ -0,0 +1,61 @@ +package diff + +import "testing" + +func TestExtractBaseTypeName(t *testing.T) { + tests := []struct { + name string + typeExpr string + want string + }{ + { + name: "simple type", + typeExpr: "integer", + want: "integer", + }, + { + name: "SETOF simple type", + typeExpr: "SETOF actor", + want: "actor", + }, + { + name: "SETOF with schema", + typeExpr: "SETOF public.actor", + want: "public.actor", + }, + { + name: "SETOF with quoted type name", + typeExpr: `SETOF public."ViewName"`, + want: "public.ViewName", + }, + { + name: "SETOF with quoted schema and type", + typeExpr: `SETOF "Schema"."ViewName"`, + want: "Schema.ViewName", + }, + { + name: "quoted type only", + typeExpr: `"MyType"`, + want: "MyType", + }, + { + name: "array type", + typeExpr: "integer[]", + want: "integer", + }, + { + name: "SETOF quoted type with array", + typeExpr: `SETOF public."ViewName"[]`, + want: "public.ViewName", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := extractBaseTypeName(tt.typeExpr) + if got != tt.want { + t.Errorf("extractBaseTypeName(%q) = %q, want %q", tt.typeExpr, got, tt.want) + } + }) + } +}