Skip to content

Commit 1114cea

Browse files
committed
Address remaining commments
1 parent a310e9f commit 1114cea

File tree

10 files changed

+162
-92
lines changed

10 files changed

+162
-92
lines changed

chasm/search_attribute.go

Lines changed: 69 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package chasm
33
import (
44
"errors"
55
"fmt"
6+
"reflect"
67
"time"
78

89
enumspb "go.temporal.io/api/enums/v1"
@@ -67,13 +68,19 @@ var (
6768
)
6869

6970
var (
70-
_ SearchAttribute = (*searchAttributeDefinition)(nil)
7171
_ SearchAttribute = (*SearchAttributeBool)(nil)
7272
_ SearchAttribute = (*SearchAttributeDateTime)(nil)
7373
_ SearchAttribute = (*SearchAttributeInt)(nil)
7474
_ SearchAttribute = (*SearchAttributeDouble)(nil)
7575
_ SearchAttribute = (*SearchAttributeKeyword)(nil)
7676
_ SearchAttribute = (*SearchAttributeKeywordList)(nil)
77+
78+
_ typedSearchAttribute[bool] = (*SearchAttributeBool)(nil)
79+
_ typedSearchAttribute[time.Time] = (*SearchAttributeDateTime)(nil)
80+
_ typedSearchAttribute[int64] = (*SearchAttributeInt)(nil)
81+
_ typedSearchAttribute[float64] = (*SearchAttributeDouble)(nil)
82+
_ typedSearchAttribute[string] = (*SearchAttributeKeyword)(nil)
83+
_ typedSearchAttribute[[]string] = (*SearchAttributeKeywordList)(nil)
7784
)
7885

7986
type (
@@ -82,6 +89,12 @@ type (
8289
definition() searchAttributeDefinition
8390
}
8491

92+
typedSearchAttribute[T any] interface {
93+
SearchAttribute
94+
typeMarker(T)
95+
markedVisibilityType() reflect.Type
96+
}
97+
8598
searchAttributeDefinition struct {
8699
alias string
87100
field string
@@ -210,6 +223,12 @@ func (s SearchAttributeBool) Value(value bool) SearchAttributeKeyValue {
210223
}
211224
}
212225

226+
func (s SearchAttributeBool) typeMarker(_ bool) {}
227+
228+
func (s SearchAttributeBool) markedVisibilityType() reflect.Type {
229+
return reflect.TypeFor[VisibilityValueBool]()
230+
}
231+
213232
// SearchAttributeDateTime is a search attribute for a datetime value.
214233
type SearchAttributeDateTime struct {
215234
searchAttributeDefinition
@@ -245,6 +264,12 @@ func (s SearchAttributeDateTime) Value(value time.Time) SearchAttributeKeyValue
245264
}
246265
}
247266

267+
func (s SearchAttributeDateTime) typeMarker(_ time.Time) {}
268+
269+
func (s SearchAttributeDateTime) markedVisibilityType() reflect.Type {
270+
return reflect.TypeFor[VisibilityValueTime]()
271+
}
272+
248273
// SearchAttributeInt is a search attribute for an integer value.
249274
type SearchAttributeInt struct {
250275
searchAttributeDefinition
@@ -280,6 +305,12 @@ func (s SearchAttributeInt) Value(value int64) SearchAttributeKeyValue {
280305
}
281306
}
282307

308+
func (s SearchAttributeInt) typeMarker(_ int64) {}
309+
310+
func (s SearchAttributeInt) markedVisibilityType() reflect.Type {
311+
return reflect.TypeFor[VisibilityValueInt64]()
312+
}
313+
283314
// SearchAttributeDouble is a search attribute for a double value.
284315
type SearchAttributeDouble struct {
285316
searchAttributeDefinition
@@ -315,6 +346,12 @@ func (s SearchAttributeDouble) Value(value float64) SearchAttributeKeyValue {
315346
}
316347
}
317348

349+
func (s SearchAttributeDouble) typeMarker(_ float64) {}
350+
351+
func (s SearchAttributeDouble) markedVisibilityType() reflect.Type {
352+
return reflect.TypeFor[VisibilityValueFloat64]()
353+
}
354+
318355
// SearchAttributeKeyword is a search attribute for a keyword value.
319356
type SearchAttributeKeyword struct {
320357
searchAttributeDefinition
@@ -350,6 +387,12 @@ func (s SearchAttributeKeyword) Value(value string) SearchAttributeKeyValue {
350387
}
351388
}
352389

390+
func (s SearchAttributeKeyword) typeMarker(_ string) {}
391+
392+
func (s SearchAttributeKeyword) markedVisibilityType() reflect.Type {
393+
return reflect.TypeFor[VisibilityValueString]()
394+
}
395+
353396
// SearchAttributeKeywordList is a search attribute for a keyword list value.
354397
type SearchAttributeKeywordList struct {
355398
searchAttributeDefinition
@@ -385,6 +428,12 @@ func (s SearchAttributeKeywordList) Value(value []string) SearchAttributeKeyValu
385428
}
386429
}
387430

431+
func (s SearchAttributeKeywordList) typeMarker(_ []string) {}
432+
433+
func (s SearchAttributeKeywordList) markedVisibilityType() reflect.Type {
434+
return reflect.TypeFor[VisibilityValueStringSlice]()
435+
}
436+
388437
// SearchAttributesMap wraps search attribute values with type-safe access.
389438
type SearchAttributesMap struct {
390439
values map[string]VisibilityValue
@@ -395,94 +444,39 @@ func NewSearchAttributesMap(values map[string]VisibilityValue) SearchAttributesM
395444
return SearchAttributesMap{values: values}
396445
}
397446

398-
// GetBool returns the boolean value for a given SearchAttributeBool. If not found or map is nil, found is false.
399-
func (m SearchAttributesMap) GetBool(sa SearchAttributeBool) (value bool, found bool) {
447+
// Get returns the value for a given SearchAttribute with compile-time type safety.
448+
// The return type T is inferred from the SearchAttribute's type parameter.
449+
// For example, SearchAttriteBool will return a bool value.
450+
// If the value is not found, the zero value for the type T is returned and the second return value is false.
451+
func Get[T any](m SearchAttributesMap, sa typedSearchAttribute[T]) (val T, ok bool) {
452+
var zero T
400453
if m.values == nil {
401-
return false, false
454+
return zero, false
402455
}
403456

404457
alias := sa.definition().alias
405-
boolVal, ok := m.values[alias].(VisibilityValueBool)
406-
if !ok {
407-
return false, false
458+
visibilityValue, exists := m.values[alias]
459+
if !exists {
460+
return zero, false
408461
}
409462

410-
return bool(boolVal), true
411-
}
412-
413-
// GetInt returns the int value for a given SearchAttributeInt. If not found or map is nil, second parameter is false.
414-
func (m SearchAttributesMap) GetInt(sa SearchAttributeInt) (int, bool) {
415-
if m.values == nil {
416-
return 0, false
463+
if reflect.TypeOf(visibilityValue) != sa.markedVisibilityType() {
464+
return zero, false
417465
}
418466

419-
alias := sa.definition().alias
420-
intValue, ok := m.values[alias].(VisibilityValueInt)
421-
if !ok {
422-
return 0, false
423-
}
424-
425-
return int(intValue), true
426-
}
467+
reflectVal := reflect.ValueOf(val)
468+
targetType := reflect.TypeFor[T]()
427469

428-
// GetDouble returns the double value for a given SearchAttributeDouble. If not found or map is nil, second parameter is false.
429-
func (m SearchAttributesMap) GetDouble(sa SearchAttributeDouble) (float64, bool) {
430-
if m.values == nil {
431-
return 0, false
432-
}
433-
434-
alias := sa.definition().alias
435-
doubleValue, ok := m.values[alias].(VisibilityValueFloat64)
436-
if !ok {
437-
return 0, false
470+
if !reflectVal.Type().ConvertibleTo(targetType) {
471+
return zero, false
438472
}
439473

440-
return float64(doubleValue), true
441-
}
442-
443-
// GetKeyword returns the string value for a given SearchAttributeKeyword. If not found or map is nil, second parameter is false.
444-
func (m SearchAttributesMap) GetKeyword(sa SearchAttributeKeyword) (string, bool) {
445-
if m.values == nil {
446-
return "", false
447-
}
448-
449-
alias := sa.definition().alias
450-
stringValue, ok := m.values[alias].(VisibilityValueString)
451-
if !ok {
452-
return "", false
453-
}
454-
455-
return string(stringValue), true
456-
}
457-
458-
// GetDateTime returns the time value for a given SearchAttributeDateTime. If not found or map is nil, second parameter is false.
459-
func (m SearchAttributesMap) GetDateTime(sa SearchAttributeDateTime) (time.Time, bool) {
460-
if m.values == nil {
461-
return time.Time{}, false
462-
}
463-
464-
alias := sa.definition().alias
465-
timeValue, ok := m.values[alias].(VisibilityValueTime)
466-
if !ok {
467-
return time.Time{}, false
468-
}
469-
470-
return time.Time(timeValue), true
471-
}
472-
473-
// GetKeywordList returns the string list value for a given SearchAttributeKeywordList. If not found or map is nil, second parameter is false.
474-
func (m SearchAttributesMap) GetKeywordList(sa SearchAttributeKeywordList) ([]string, bool) {
475-
if m.values == nil {
476-
return nil, false
477-
}
478-
479-
alias := sa.definition().alias
480-
keywordListValue, ok := m.values[alias].(VisibilityValueStringSlice)
474+
result, ok := reflectVal.Convert(targetType).Interface().(T)
481475
if !ok {
482-
return nil, false
476+
return zero, false
483477
}
484478

485-
return []string(keywordListValue), true
479+
return result, true
486480
}
487481

488482
// convertToVisibilityValue converts a value to VisibilityValue based on its runtime type.

chasm/search_attribute_test.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package chasm
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func TestSearchAttributesMap_Get(t *testing.T) {
11+
// Define test search attributes
12+
boolAttr := NewSearchAttributeBool("completed", SearchAttributeFieldBool01)
13+
intAttr := NewSearchAttributeInt("count", SearchAttributeFieldInt01)
14+
doubleAttr := NewSearchAttributeDouble("score", SearchAttributeFieldDouble01)
15+
keywordAttr := NewSearchAttributeKeyword("status", SearchAttributeFieldKeyword01)
16+
datetimeAttr := NewSearchAttributeDateTime("timestamp", SearchAttributeFieldDateTime01)
17+
keywordListAttr := NewSearchAttributeKeywordList("tags", SearchAttributeFieldKeywordList01)
18+
19+
now := time.Now()
20+
21+
// Create map with test values
22+
values := map[string]VisibilityValue{
23+
"completed": VisibilityValueBool(true),
24+
"count": VisibilityValueInt64(42),
25+
"score": VisibilityValueFloat64(3.14),
26+
"status": VisibilityValueString("active"),
27+
"timestamp": VisibilityValueTime(now),
28+
"tags": VisibilityValueStringSlice([]string{"tag1", "tag2"}),
29+
}
30+
m := NewSearchAttributesMap(values)
31+
32+
t.Run("GetBool", func(t *testing.T) {
33+
val, ok := Get(m, boolAttr)
34+
assert.True(t, ok)
35+
assert.True(t, val)
36+
})
37+
38+
t.Run("GetInt64", func(t *testing.T) {
39+
val, ok := Get(m, intAttr)
40+
assert.True(t, ok)
41+
assert.Equal(t, int64(42), val)
42+
})
43+
44+
t.Run("GetFloat64", func(t *testing.T) {
45+
val, ok := Get(m, doubleAttr)
46+
assert.True(t, ok)
47+
assert.InDelta(t, 3.14, val, 0.0001)
48+
})
49+
50+
t.Run("GetString", func(t *testing.T) {
51+
val, ok := Get(m, keywordAttr)
52+
assert.True(t, ok)
53+
assert.Equal(t, "active", val)
54+
})
55+
56+
t.Run("GetTime", func(t *testing.T) {
57+
val, ok := Get(m, datetimeAttr)
58+
assert.True(t, ok)
59+
assert.True(t, now.Equal(val))
60+
})
61+
62+
t.Run("GetStringSlice", func(t *testing.T) {
63+
val, ok := Get(m, keywordListAttr)
64+
assert.True(t, ok)
65+
assert.Equal(t, []string{"tag1", "tag2"}, val)
66+
})
67+
68+
t.Run("NotFound", func(t *testing.T) {
69+
missingAttr := NewSearchAttributeBool("missing", SearchAttributeFieldBool02)
70+
val, ok := Get(m, missingAttr)
71+
assert.False(t, ok)
72+
assert.False(t, val)
73+
})
74+
75+
t.Run("NilMap", func(t *testing.T) {
76+
emptyMap := NewSearchAttributesMap(nil)
77+
val, ok := Get(emptyMap, boolAttr)
78+
assert.False(t, ok)
79+
assert.False(t, val)
80+
})
81+
}

common/persistence/visibility/manager/visibility_manager.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ type (
3636
ListWorkflowExecutions(ctx context.Context, request *ListWorkflowExecutionsRequestV2) (*ListWorkflowExecutionsResponse, error)
3737
ListChasmExecutions(ctx context.Context, request *ListChasmExecutionsRequest) (*chasm.ListExecutionsResponse[*commonpb.Payload], error)
3838
CountWorkflowExecutions(ctx context.Context, request *CountWorkflowExecutionsRequest) (*CountWorkflowExecutionsResponse, error)
39-
CountChasmExecutions(ctx context.Context, request *CountChasmExecutionsRequest) (*CountChasmExecutionsResponse, error)
39+
CountChasmExecutions(ctx context.Context, request *CountChasmExecutionsRequest) (*chasm.CountExecutionsResponse, error)
4040
GetWorkflowExecution(ctx context.Context, request *GetWorkflowExecutionRequest) (*GetWorkflowExecutionResponse, error)
4141

4242
// Admin APIs

common/persistence/visibility/manager/visibility_manager_mock.go

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

common/persistence/visibility/visibility_manager_dual.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ func (v *VisibilityManagerDual) CountWorkflowExecutions(
190190
func (v *VisibilityManagerDual) CountChasmExecutions(
191191
ctx context.Context,
192192
request *manager.CountChasmExecutionsRequest,
193-
) (*manager.CountChasmExecutionsResponse, error) {
193+
) (*chasm.CountExecutionsResponse, error) {
194194
return dualReadWrapper(
195195
ctx,
196196
v,

common/persistence/visibility/visibility_manager_impl.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,13 +211,13 @@ func (p *visibilityManagerImpl) ListChasmExecutions(
211211
func (p *visibilityManagerImpl) CountChasmExecutions(
212212
ctx context.Context,
213213
request *manager.CountChasmExecutionsRequest,
214-
) (*manager.CountChasmExecutionsResponse, error) {
214+
) (*chasm.CountExecutionsResponse, error) {
215215
response, err := p.store.CountChasmExecutions(ctx, request)
216216
if err != nil {
217217
return nil, err
218218
}
219219

220-
return response, nil
220+
return &chasm.CountExecutionsResponse{Count: response.Count}, nil
221221
}
222222

223223
func (p *visibilityManagerImpl) CountWorkflowExecutions(

common/persistence/visibility/visibility_manager_rate_limited.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ func (m *visibilityManagerRateLimited) CountWorkflowExecutions(
141141
func (m *visibilityManagerRateLimited) CountChasmExecutions(
142142
ctx context.Context,
143143
request *manager.CountChasmExecutionsRequest,
144-
) (*manager.CountChasmExecutionsResponse, error) {
144+
) (*chasm.CountExecutionsResponse, error) {
145145
if ok := allow(ctx, "CountChasmExecutions", m.readRateLimiter); !ok {
146146
return nil, persistence.ErrPersistenceSystemLimitExceeded
147147
}

common/persistence/visibility/visiblity_manager_metrics.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ func (m *visibilityManagerMetrics) CountWorkflowExecutions(
162162
func (m *visibilityManagerMetrics) CountChasmExecutions(
163163
ctx context.Context,
164164
request *manager.CountChasmExecutionsRequest,
165-
) (*manager.CountChasmExecutionsResponse, error) {
165+
) (*chasm.CountExecutionsResponse, error) {
166166
handler, startTime := m.tagScope(metrics.VisibilityPersistenceCountChasmExecutionsScope)
167167
response, err := m.delegate.CountChasmExecutions(ctx, request)
168168
metrics.VisibilityPersistenceLatency.With(handler).Record(time.Since(startTime))

service/history/chasm_engine.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -670,15 +670,10 @@ func (e *ChasmEngine) CountExecutions(
670670
return nil, serviceerror.NewInternal("unknown chasm component type: " + archetypeType.String())
671671
}
672672

673-
resp, err := e.visibilityMgr.CountChasmExecutions(ctx, &manager.CountChasmExecutionsRequest{
673+
return e.visibilityMgr.CountChasmExecutions(ctx, &manager.CountChasmExecutionsRequest{
674674
ArchetypeID: archetypeID,
675675
NamespaceID: namespace.ID(request.NamespaceID),
676676
Namespace: namespace.Name(request.NamespaceName),
677677
Query: request.Query,
678678
})
679-
if err != nil {
680-
return nil, err
681-
}
682-
683-
return &chasm.CountExecutionsResponse{Count: resp.Count}, nil
684679
}

0 commit comments

Comments
 (0)