Skip to content

Commit 8cd25ec

Browse files
committed
Add typed_search_attributes workflow option
1 parent 5bef6e9 commit 8cd25ec

File tree

39 files changed

+3060
-77
lines changed

39 files changed

+3060
-77
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
kind: Added
2+
body: Add typed_search_attributes workflow option
3+
time: 2025-11-17T09:56:39.580517-07:00
4+
custom:
5+
Author: cludden
6+
PullRequest: "131"

buf.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ deps:
88
commit: 76b304caf5984a3a978e9565ea71a2ac
99
digest: b5:72c441888d19ff57f824b75f59aba0346a16bfa3ef5da83a5da21c614f0763764e1d37511312dc82f54e1dae5937a5829e8c2c1b7f806c983046bbf624b04ac2
1010
- name: buf.build/cludden/protoc-gen-go-temporal
11-
commit: cb7ac4e77f4e475aa01c09ea6863b8bd
12-
digest: b5:cc480cc2d12ad1f4a5a7cfee696f61aadca27496b36790541f63f1a5e12d9178ae03bb79fd615322951425d298fce2f69ea0d7971270cf4fdb519df7bdfc6daa
11+
commit: 706631d1caec4f1ab4f4421f5d9dc0cb
12+
digest: b5:2b39f97ce9904f30deb02a9105c11ff9a0b9ce119aef8a5a3d2d1138f3c3c5202f7917ab78dcc6bae10f17875399e07b408efd105084438c5f235c333b268bbd
1313
- name: buf.build/envoyproxy/protoc-gen-validate
1414
commit: daf171c6cdb54629b5f51e345a79e4dd
1515
digest: b5:c745e1521879f43740230b1df673d0729f55704efefdcfc489d4a0a2d40c92a26cacfeab62813403040a8b180142d53b398c7ca784a065e43823605ee49681de
1616
- name: buf.build/googleapis/googleapis
1717
commit: 28151c0d0a1641bf938a7672c500e01d
1818
digest: b5:93b70089baa4fc05a92d3e52db91a4b7812db3b57b9664f6cb301733938cb630e377a938e8a56779388171c749c1d42a2e9a6c6230f2ff45f127a8102a6a27d0
1919
- name: buf.build/temporalio/api
20-
commit: b3c9abfdf37c449593a3c0d2774a3618
21-
digest: b5:c123e858dba36871e9e604ff5fe6e3e1a8188238929fda76dc5d4297630c1a3bea35b4dd9ef27c665c4c77d34b327de6971dbe9ef57845a6727166cc61494167
20+
commit: 145e888ec59442288b19a82a03d6397e
21+
digest: b5:0c0f925b43db1f56b0b5f9a480cd0d7b8f318d7a0369c6b310002bed1d5b4ea922b542d6cf43027810e36b98e4ef3685df8ed8f91cc3d11fcfa2c16bfb8b00d9

docs/docs/configuration/workflow.mdx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,29 @@ service Example {
366366
}
367367
```
368368

369+
### typed_search_attributes
370+
371+
`string`
372+
373+
Specifies the default [Workflow typed search attributes](https://docs.temporal.io/visibility#search-attribute) as a [Bloblang mapping](https://www.benthos.dev/docs/guides/bloblang/about/) that returns a map of search attribute types to a map of search attribute keys to values. See the [Search Attributes example](/docs/examples/searchattributes/) for more details.
374+
375+
```protobuf
376+
service Example {
377+
rpc Hello(HelloInput) returns (HelloOutput) {
378+
option (temporal.v1.workflow) = {
379+
typed_search_attributes:
380+
'keyword.CustomKeywordField = customKeywordField \n'
381+
'string.CustomTextField = customTextField \n'
382+
'int64.CustomIntField = customIntField.int64() \n'
383+
'float64.CustomDoubleField = customDoubleField \n'
384+
'bool.CustomBoolField = customBoolField \n'
385+
'time.CustomDatetimeField = customDatetimeField.ts_parse("2006-01-02T15:04:05Z") \n'
386+
'keyword_list.CustomKeywordListField = customKeywordListField \n'
387+
};
388+
}
389+
}
390+
```
391+
369392
### update
370393

371394
[temporal.v1.WorkflowOptions.Update](https://buf.build/cludden/protoc-gen-go-temporal/docs/main:temporal.v1#temporal.v1.WorkflowOptions.Update)

examples/searchattributes/main.go

Lines changed: 70 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,49 @@ import (
1111
"go.temporal.io/sdk/client"
1212
"go.temporal.io/sdk/converter"
1313
tlog "go.temporal.io/sdk/log"
14+
"go.temporal.io/sdk/temporal"
1415
"go.temporal.io/sdk/worker"
1516
"go.temporal.io/sdk/workflow"
17+
"google.golang.org/protobuf/types/known/timestamppb"
1618
)
1719

20+
var (
21+
customKeywordField = temporal.NewSearchAttributeKeyKeyword("CustomKeywordField")
22+
customKeywordListField = temporal.NewSearchAttributeKeyKeywordList("CustomKeywordListField")
23+
customTextField = temporal.NewSearchAttributeKeyString("CustomTextField")
24+
customIntField = temporal.NewSearchAttributeKeyInt64("CustomIntField")
25+
customDoubleField = temporal.NewSearchAttributeKeyFloat64("CustomDoubleField")
26+
customBoolField = temporal.NewSearchAttributeKeyBool("CustomBoolField")
27+
customDatetimeField = temporal.NewSearchAttributeKeyTime("CustomDatetimeField")
28+
)
29+
30+
func main() {
31+
app, err := searchattributesv1.NewExampleCli(
32+
searchattributesv1.NewExampleCliOptions().WithWorker(func(cmd *cli.Context, c client.Client) (worker.Worker, error) {
33+
w := worker.New(c, searchattributesv1.ExampleTaskQueue, worker.Options{})
34+
searchattributesv1.RegisterExampleWorkflows(w, &Workflows{})
35+
return w, nil
36+
}),
37+
)
38+
if err != nil {
39+
log.Fatal(err)
40+
}
41+
if err := app.Run(os.Args); err != nil {
42+
log.Fatal(err)
43+
}
44+
}
45+
46+
type Workflows struct{}
47+
1848
type SearchAttributesWorkflow struct {
1949
*searchattributesv1.SearchAttributesWorkflowInput
2050
log tlog.Logger
2151
}
2252

23-
func NewSearchAttributesWorkflow(ctx workflow.Context, input *searchattributesv1.SearchAttributesWorkflowInput) (searchattributesv1.SearchAttributesWorkflow, error) {
53+
func (w *Workflows) SearchAttributes(
54+
ctx workflow.Context,
55+
input *searchattributesv1.SearchAttributesWorkflowInput,
56+
) (searchattributesv1.SearchAttributesWorkflow, error) {
2457
return &SearchAttributesWorkflow{input, workflow.GetLogger(ctx)}, nil
2558
}
2659

@@ -60,18 +93,42 @@ func (w *SearchAttributesWorkflow) Execute(ctx workflow.Context) (err error) {
6093
return nil
6194
}
6295

63-
func main() {
64-
app, err := searchattributesv1.NewExampleCli(
65-
searchattributesv1.NewExampleCliOptions().WithWorker(func(cmd *cli.Context, c client.Client) (worker.Worker, error) {
66-
w := worker.New(c, searchattributesv1.ExampleTaskQueue, worker.Options{})
67-
searchattributesv1.RegisterSearchAttributesWorkflow(w, NewSearchAttributesWorkflow)
68-
return w, nil
69-
}),
70-
)
71-
if err != nil {
72-
log.Fatal(err)
96+
type TypedSearchAttributesWorkflow struct {
97+
*searchattributesv1.TypedSearchAttributesWorkflowInput
98+
log tlog.Logger
99+
}
100+
101+
func (w *Workflows) TypedSearchAttributes(
102+
ctx workflow.Context, input *searchattributesv1.TypedSearchAttributesWorkflowInput,
103+
) (searchattributesv1.TypedSearchAttributesWorkflow, error) {
104+
return &TypedSearchAttributesWorkflow{input, workflow.GetLogger(ctx)}, nil
105+
}
106+
107+
func (w *TypedSearchAttributesWorkflow) Execute(
108+
ctx workflow.Context,
109+
) (*searchattributesv1.TypedSearchAttributesOutput, error) {
110+
out := &searchattributesv1.TypedSearchAttributesOutput{}
111+
sa := workflow.GetTypedSearchAttributes(ctx)
112+
if v, ok := sa.GetKeyword(customKeywordField); ok {
113+
out.CustomKeywordField = v
73114
}
74-
if err := app.Run(os.Args); err != nil {
75-
log.Fatal(err)
115+
if v, ok := sa.GetFloat64(customDoubleField); ok {
116+
out.CustomDoubleField = v
117+
}
118+
if v, ok := sa.GetBool(customBoolField); ok {
119+
out.CustomBoolField = v
120+
}
121+
if v, ok := sa.GetTime(customDatetimeField); ok {
122+
out.CustomDatetimeField = timestamppb.New(v)
123+
}
124+
if v, ok := sa.GetKeywordList(customKeywordListField); ok {
125+
out.CustomKeywordListField = v
126+
}
127+
if v, ok := sa.GetString(customTextField); ok {
128+
out.CustomTextField = v
129+
}
130+
if v, ok := sa.GetInt64(customIntField); ok {
131+
out.CustomIntField = v
76132
}
133+
return out, nil
77134
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"testing"
6+
"time"
7+
8+
searchattributesv1 "github.com/cludden/protoc-gen-go-temporal/gen/example/searchattributes/v1"
9+
"github.com/hairyhenderson/go-which"
10+
"github.com/stretchr/testify/require"
11+
"go.temporal.io/api/enums/v1"
12+
"go.temporal.io/api/operatorservice/v1"
13+
"go.temporal.io/sdk/testsuite"
14+
"go.temporal.io/sdk/worker"
15+
"google.golang.org/protobuf/types/known/timestamppb"
16+
)
17+
18+
func TestTypedSearchAttributes(t *testing.T) {
19+
existingPath := which.Which("temporal")
20+
if existingPath == "" {
21+
t.Skip("temporal binary not found in PATH, skipping test")
22+
}
23+
srv, err := testsuite.StartDevServer(context.Background(), testsuite.DevServerOptions{})
24+
require.NoError(t, err)
25+
t.Cleanup(func() { require.NoError(t, srv.Stop()) })
26+
27+
c := srv.Client()
28+
_, err = c.OperatorService().AddSearchAttributes(context.Background(), &operatorservice.AddSearchAttributesRequest{
29+
Namespace: "default",
30+
SearchAttributes: map[string]enums.IndexedValueType{
31+
"CustomKeywordField": enums.INDEXED_VALUE_TYPE_KEYWORD,
32+
"CustomKeywordListField": enums.INDEXED_VALUE_TYPE_KEYWORD_LIST,
33+
"CustomTextField": enums.INDEXED_VALUE_TYPE_TEXT,
34+
"CustomIntField": enums.INDEXED_VALUE_TYPE_INT,
35+
"CustomDoubleField": enums.INDEXED_VALUE_TYPE_DOUBLE,
36+
"CustomBoolField": enums.INDEXED_VALUE_TYPE_BOOL,
37+
"CustomDatetimeField": enums.INDEXED_VALUE_TYPE_DATETIME,
38+
},
39+
})
40+
require.NoError(t, err)
41+
42+
client := searchattributesv1.NewExampleClient(c)
43+
w := worker.New(c, searchattributesv1.ExampleTaskQueue, worker.Options{})
44+
searchattributesv1.RegisterExampleWorkflows(w, &Workflows{})
45+
require.NoError(t, w.Start())
46+
t.Cleanup(w.Stop)
47+
48+
now := time.Now().UTC()
49+
out, err := client.TypedSearchAttributes(context.Background(), &searchattributesv1.TypedSearchAttributesInput{
50+
CustomKeywordField: "test",
51+
CustomTextField: "test",
52+
CustomIntField: 123,
53+
CustomDoubleField: 123.456,
54+
CustomBoolField: true,
55+
CustomDatetimeField: timestamppb.New(now),
56+
CustomKeywordListField: []string{"test"},
57+
})
58+
require.NoError(t, err)
59+
require.Equal(t, "test", out.CustomKeywordField)
60+
require.Equal(t, "test", out.CustomTextField)
61+
require.Equal(t, int64(123), out.CustomIntField)
62+
require.Equal(t, 123.456, out.CustomDoubleField)
63+
require.Equal(t, true, out.CustomBoolField)
64+
require.Equal(t, now, out.CustomDatetimeField.AsTime())
65+
require.Equal(t, []string{"test"}, out.CustomKeywordListField)
66+
}

examples/searchattributes/proto/example/searchattributes/v1/searchattributes.proto

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,20 @@ service Example {
2121
'CustomDatetimeField = customDatetimeField.ts_parse("2006-01-02T15:04:05Z") \n'
2222
};
2323
}
24+
25+
rpc TypedSearchAttributes(TypedSearchAttributesInput) returns (TypedSearchAttributesOutput) {
26+
option (temporal.v1.workflow) = {
27+
id: 'searchattributes.v1.TypedSearchAttributes/${! uuid_v4() }'
28+
typed_search_attributes:
29+
'keyword.CustomKeywordField = customKeywordField \n'
30+
'string.CustomTextField = customTextField \n'
31+
'int64.CustomIntField = customIntField.int64() \n'
32+
'float64.CustomDoubleField = customDoubleField \n'
33+
'bool.CustomBoolField = customBoolField \n'
34+
'time.CustomDatetimeField = customDatetimeField.ts_parse("2006-01-02T15:04:05Z") \n'
35+
'keyword_list.CustomKeywordListField = customKeywordListField \n'
36+
};
37+
}
2438
}
2539

2640
message SearchAttributesInput {
@@ -31,3 +45,23 @@ message SearchAttributesInput {
3145
bool custom_bool_field = 5;
3246
google.protobuf.Timestamp custom_datetime_field = 6;
3347
}
48+
49+
message TypedSearchAttributesInput {
50+
string custom_keyword_field = 1;
51+
string custom_text_field = 2;
52+
int64 custom_int_field = 3;
53+
double custom_double_field = 4;
54+
bool custom_bool_field = 5;
55+
google.protobuf.Timestamp custom_datetime_field = 6;
56+
repeated string custom_keyword_list_field = 7;
57+
}
58+
59+
message TypedSearchAttributesOutput {
60+
string custom_keyword_field = 1;
61+
string custom_text_field = 2;
62+
int64 custom_int_field = 3;
63+
double custom_double_field = 4;
64+
bool custom_bool_field = 5;
65+
google.protobuf.Timestamp custom_datetime_field = 6;
66+
repeated string custom_keyword_list_field = 7;
67+
}

gen/example/helloworld/v1/example_temporal.pb.go

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

0 commit comments

Comments
 (0)