Repository: xataio/pgstream
Pull request #438 (2025-07-14 13:29:52)

[Search Processor] Handle uuid type for search mapping
This PR updates the search mapping to handle UUID types properly, by making them supported identity types and parsing values to use the string representation.

Fixes #433 


Patch:
diff --git a/pkg/wal/processor/search/search_adapter.go b/pkg/wal/processor/search/search_adapter.go
index fd80883..0cbf0c3 100644
--- a/pkg/wal/processor/search/search_adapter.go
+++ b/pkg/wal/processor/search/search_adapter.go
@@ -7,6 +7,7 @@ import (
 	"fmt"
 	"strconv"
 
+	"github.com/google/uuid"
 	"github.com/xataio/pgstream/internal/json"
 	"github.com/xataio/pgstream/pkg/schemalog"
 	"github.com/xataio/pgstream/pkg/wal"
@@ -256,6 +257,8 @@ func (a *adapter) parseIDColumns(tableName string, idColumns []wal.Column, doc *
 			addToID(strconv.FormatInt(v, 10))
 		case float64:
 			addToID(strconv.FormatFloat(v, 'f', -1, 64))
+		case [16]uint8: // UUID
+			addToID(uuid.UUID(v).String())
 		case nil:
 			return errNilIDValue
 		default:
diff --git a/pkg/wal/processor/search/store/search_pg_mapper.go b/pkg/wal/processor/search/store/search_pg_mapper.go
index a064dad..271c904 100644
--- a/pkg/wal/processor/search/store/search_pg_mapper.go
+++ b/pkg/wal/processor/search/store/search_pg_mapper.go
@@ -8,6 +8,7 @@ import (
 	"strings"
 	"time"
 
+	"github.com/google/uuid"
 	"github.com/jackc/pgx/v5/pgtype"
 
 	"github.com/xataio/pgstream/internal/json"
@@ -89,9 +90,24 @@ func (m *PgMapper) MapColumnValue(column schemalog.Column, value any) (any, erro
 			return nil, fmt.Errorf("vector value is not array: %w", err)
 		}
 		return array, nil
+	case searchstore.StringType:
+		if column.DataType == "uuid" {
+			// handle uuid type for cases when the uuid is represented as a
+			// [16]uint8, we need to convert it to a string
+			if uuidBytes, ok := value.([16]uint8); ok {
+				return uuid.UUID(uuidBytes).String(), nil
+			}
+		}
+		if searchField.IsArray {
+			// handle arrays of strings
+			var a pgtype.FlatArray[string]
+			err := m.pgTypeMap.SQLScanner(&a).Scan(value)
+			return []string(a), err
+		}
+		return value, nil
 	default:
-		if searchField.IsArray { // catches all other array types
-			// handle arrays
+		if searchField.IsArray {
+			// catches all other array types
 			switch searchField.SearchType {
 			case searchstore.IntegerType:
 				var a pgtype.FlatArray[int64]
@@ -105,10 +121,6 @@ func (m *PgMapper) MapColumnValue(column schemalog.Column, value any) (any, erro
 				var a pgtype.FlatArray[bool]
 				err := m.pgTypeMap.SQLScanner(&a).Scan(value)
 				return []bool(a), err
-			case searchstore.StringType:
-				var a pgtype.FlatArray[string]
-				err := m.pgTypeMap.SQLScanner(&a).Scan(value)
-				return []string(a), err
 			case searchstore.JSONType:
 				// nothing to do for json array types
 			default:


Test patch:
diff --git a/pkg/wal/processor/search/search_adapter_test.go b/pkg/wal/processor/search/search_adapter_test.go
index eac19d7..18233e6 100644
--- a/pkg/wal/processor/search/search_adapter_test.go
+++ b/pkg/wal/processor/search/search_adapter_test.go
@@ -624,6 +624,7 @@ func TestAdapter_parseIDColumns(t *testing.T) {
 			Data: make(map[string]any),
 		}
 	}
+	testUUID := "99d4f38c-770a-460e-b0ac-419fbc3d5636"
 
 	testTable := "test-table"
 	tests := []struct {
@@ -665,6 +666,14 @@ func TestAdapter_parseIDColumns(t *testing.T) {
 			wantDoc: newDoc(fmt.Sprintf("%s_1", testTable)),
 			wantErr: nil,
 		},
+		{
+			name: "ok - [16]uint8 (UUID)",
+			idColumns: []wal.Column{
+				{Name: "id-1", Value: [16]uint8{153, 212, 243, 140, 119, 10, 70, 14, 176, 172, 65, 159, 188, 61, 86, 54}},
+			},
+			wantDoc: newDoc(fmt.Sprintf("%s_%s", testTable, testUUID)),
+			wantErr: nil,
+		},
 		{
 			name: "ok - multiple id columns",
 			idColumns: []wal.Column{
diff --git a/pkg/wal/processor/search/store/search_pg_mapper_test.go b/pkg/wal/processor/search/store/search_pg_mapper_test.go
index 5a10e47..f9d3721 100644
--- a/pkg/wal/processor/search/store/search_pg_mapper_test.go
+++ b/pkg/wal/processor/search/store/search_pg_mapper_test.go
@@ -268,7 +268,23 @@ func TestMapper_MapColumnValue(t *testing.T) {
 			wantErr:   nil,
 		},
 		{
-			name:   "unknonwn column type",
+			name:   "uuid",
+			column: schemalog.Column{DataType: "uuid"},
+			value:  [16]uint8{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0},
+
+			wantValue: "12345678-9abc-def0-1234-56789abcdef0",
+			wantErr:   nil,
+		},
+		{
+			name:   "string array",
+			column: schemalog.Column{DataType: "text[]"},
+			value:  "{value1,value2}",
+
+			wantValue: []string{"value1", "value2"},
+			wantErr:   nil,
+		},
+		{
+			name:   "unknown column type",
 			column: schemalog.Column{DataType: "custom_type"},
 			value:  "value",