@@ -4,8 +4,10 @@ package searchattribute
44
55import (
66 "errors"
7+ "fmt"
78
89 commonpb "go.temporal.io/api/common/v1"
10+ enumspb "go.temporal.io/api/enums/v1"
911 "go.temporal.io/api/serviceerror"
1012 "go.temporal.io/server/common/namespace"
1113 "go.temporal.io/server/common/searchattribute/sadefs"
@@ -20,101 +22,106 @@ type (
2022 GetFieldName (alias string , namespace string ) (string , error )
2123 }
2224
23- noopMapper struct {}
24-
25- // This mapper is to be backwards compatible with versions before v1.20.
26- // Users using standard visibility might have registered custom search attributes.
27- // Those search attributes won't be searchable, as they weren't before version v1.20.
28- // Thus, this mapper will allow those search attributes to be used without being alised.
29- backCompMapper_v1_20 struct {
30- mapper Mapper
31- emptyStringNameTypeMap NameTypeMap
25+ // This mapper preserves legacy custom search attribute behavior by falling back
26+ // to identity mapping when the wrapped mapper misses but cluster metadata still
27+ // recognizes the name as a legacy custom search attribute.
28+ backCompMapper struct {
29+ mapper Mapper
30+ fallbackNameTypeMap NameTypeMap
3231 }
3332
3433 MapperProvider interface {
3534 GetMapper (nsName namespace.Name ) (Mapper , error )
3635 }
3736
3837 mapperProviderImpl struct {
39- customMapper Mapper
40- namespaceRegistry namespace.Registry
41- searchAttributesProvider Provider
42- enableMapperFromNamespace bool
38+ customMapper Mapper
39+ namespaceRegistry namespace.Registry
40+ searchAttributesProvider Provider
41+ fallbackIndexName string
4342 }
4443)
4544
46- var _ Mapper = (* noopMapper )(nil )
47- var _ Mapper = (* backCompMapper_v1_20 )(nil )
45+ var _ Mapper = (* backCompMapper )(nil )
4846var _ Mapper = (* namespace .CustomSearchAttributesMapper )(nil )
4947var _ MapperProvider = (* mapperProviderImpl )(nil )
5048
51- func (m * noopMapper ) GetAlias (fieldName string , _ string ) (string , error ) {
52- return fieldName , nil
53- }
54-
55- func (m * noopMapper ) GetFieldName (alias string , _ string ) (string , error ) {
56- return alias , nil
57- }
58-
59- func (m * backCompMapper_v1_20 ) GetAlias (fieldName string , namespaceName string ) (string , error ) {
49+ func (m * backCompMapper ) GetAlias (fieldName string , namespaceName string ) (string , error ) {
6050 alias , firstErr := m .mapper .GetAlias (fieldName , namespaceName )
6151 if firstErr != nil {
62- _ , err := m .emptyStringNameTypeMap .getType (fieldName , customCategory )
63- if err != nil {
52+ if ! m .isLegacyCustomSearchAttribute (fieldName ) {
6453 return "" , firstErr
6554 }
66- // this is custom search attribute registered in pre-v1.20
55+ // this is a custom search attribute registered through cluster metadata.
6756 return fieldName , nil
6857 }
6958 return alias , nil
7059}
7160
72- func (m * backCompMapper_v1_20 ) GetFieldName (alias string , namespaceName string ) (string , error ) {
61+ func (m * backCompMapper ) GetFieldName (alias string , namespaceName string ) (string , error ) {
7362 fieldName , firstErr := m .mapper .GetFieldName (alias , namespaceName )
7463 if firstErr != nil {
75- _ , err := m .emptyStringNameTypeMap .getType (alias , customCategory )
76- if err != nil {
64+ if ! m .isLegacyCustomSearchAttribute (alias ) {
7765 return "" , firstErr
7866 }
79- // this is custom search attribute registered in pre-v1.20
67+ // this is a custom search attribute registered through cluster metadata.
8068 return alias , nil
8169 }
8270 return fieldName , nil
8371}
8472
73+ func (m * backCompMapper ) isLegacyCustomSearchAttribute (name string ) bool {
74+ _ , err := m .fallbackNameTypeMap .getType (name , customCategory )
75+ return err == nil
76+ }
77+
8578func NewMapperProvider (
8679 customMapper Mapper ,
8780 namespaceRegistry namespace.Registry ,
8881 searchAttributesProvider Provider ,
89- enableMapperFromNamespace bool ,
82+ fallbackIndexName string ,
9083) MapperProvider {
9184 return & mapperProviderImpl {
92- customMapper : customMapper ,
93- namespaceRegistry : namespaceRegistry ,
94- searchAttributesProvider : searchAttributesProvider ,
95- enableMapperFromNamespace : enableMapperFromNamespace ,
85+ customMapper : customMapper ,
86+ namespaceRegistry : namespaceRegistry ,
87+ searchAttributesProvider : searchAttributesProvider ,
88+ fallbackIndexName : fallbackIndexName ,
9689 }
9790}
9891
9992func (m * mapperProviderImpl ) GetMapper (nsName namespace.Name ) (Mapper , error ) {
10093 if m .customMapper != nil {
10194 return m .customMapper , nil
10295 }
103- if ! m .enableMapperFromNamespace {
104- return & noopMapper {}, nil
105- }
10696 saMapper , err := m .namespaceRegistry .GetCustomSearchAttributesMapper (nsName )
10797 if err != nil {
10898 return nil , err
10999 }
110- // if there's an error, it returns an empty object, which is expected here
111- emptyStringNameTypeMap , _ := m .searchAttributesProvider .GetSearchAttributes ("" , false )
112- return & backCompMapper_v1_20 {
113- mapper : & saMapper ,
114- emptyStringNameTypeMap : emptyStringNameTypeMap ,
100+ fallbackNameTypeMap := NameTypeMap {}
101+ if m .fallbackIndexName != "" {
102+ nameTypeMap , err := m .searchAttributesProvider .GetSearchAttributes (m .fallbackIndexName , false )
103+ if err != nil {
104+ return nil , fmt .Errorf ("failed to load search attributes for fallback index %q: %w" , m .fallbackIndexName , err )
105+ }
106+ fallbackNameTypeMap = legacyCustomSearchAttributes (nameTypeMap )
107+ }
108+ return & backCompMapper {
109+ mapper : & saMapper ,
110+ fallbackNameTypeMap : fallbackNameTypeMap ,
115111 }, nil
116112}
117113
114+ func legacyCustomSearchAttributes (nameTypeMap NameTypeMap ) NameTypeMap {
115+ legacyCustomSearchAttributes := make (map [string ]enumspb.IndexedValueType )
116+ for name , valueType := range nameTypeMap .Custom () {
117+ if sadefs .IsPreallocatedCSAFieldName (name , valueType ) {
118+ continue
119+ }
120+ legacyCustomSearchAttributes [name ] = valueType
121+ }
122+ return NewNameTypeMap (legacyCustomSearchAttributes )
123+ }
124+
118125// AliasFields returns SearchAttributes struct where each custom search attribute name is replaced with alias.
119126// If no replacement where made, it returns nil which means that original SearchAttributes struct should be used.
120127func AliasFields (
0 commit comments