Skip to content
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
8d45ce3
Add CHASM Visibility registration and task processing
awln-temporal Oct 15, 2025
dd5301f
Remove unused code
awln-temporal Oct 15, 2025
bf50c0a
simplify search attribute constructor methods
awln-temporal Oct 16, 2025
358a354
Update linters
awln-temporal Oct 17, 2025
c103f5f
Update implementation to use separate mapper and search attribute pro…
awln-temporal Oct 21, 2025
100cdce
Remove unused code for the RegistrableComponent
awln-temporal Oct 21, 2025
cad4f71
Remove unused variable name ref
awln-temporal Oct 21, 2025
34b9c4a
Add compile time checks for the mapper interface
awln-temporal Oct 21, 2025
cc8a8b0
Rename SetValue to ValueSet
awln-temporal Oct 21, 2025
e928a2d
revert visibility queue task executor
awln-temporal Oct 21, 2025
6ee5c7f
Move attribute to global variable
awln-temporal Oct 21, 2025
c3ae24b
Change search attribute index constructors to constant refs
awln-temporal Oct 21, 2025
6cbbf09
Move mapper provider to RegistrableComponent
awln-temporal Oct 21, 2025
c7df243
Add panic check in component registration
awln-temporal Oct 21, 2025
92d5c4a
Add upsert memo method
awln-temporal Oct 21, 2025
aebc387
Move validation to registration call
awln-temporal Oct 21, 2025
dacfea5
Change search attribute provider interface to list of SearchAttribute…
awln-temporal Oct 22, 2025
bd03919
Move exported search attribute field constants to top of file
awln-temporal Oct 22, 2025
4bdd20c
address accessor comments
awln-temporal Oct 23, 2025
438f71a
Refactor conversion of []SearchAttributeKeyValue to shared map
awln-temporal Oct 23, 2025
fd7f41d
Add error return type for mapper provider interface
awln-temporal Oct 23, 2025
cfccb46
Change accessor level of predefined CHASM search attribute constructor
awln-temporal Oct 23, 2025
bb107ff
Add compile time type checks
awln-temporal Oct 23, 2025
10e9e45
Change acceessor back to public to fix unit tests
awln-temporal Oct 23, 2025
cd1339f
Update chasm search attribute documentation and mapper interface
awln-temporal Oct 23, 2025
f7d4eb2
Fix linter issue
awln-temporal Oct 24, 2025
5c46ffc
Shorten field name resolution
awln-temporal Oct 24, 2025
fdc9951
Amend test search attribute accessor level
awln-temporal Oct 24, 2025
7f9c611
Fix linter issues
awln-temporal Oct 24, 2025
528ada8
Address PR comments
awln-temporal Oct 24, 2025
3a14adc
Move validation to component instantiation
awln-temporal Oct 27, 2025
b52cdd4
Rename method names
awln-temporal Oct 27, 2025
d66929a
Merge branch 'main' into CHASMSearchAttributeComponents
awln-temporal Oct 28, 2025
4182664
Add functional tests for CHASM search attributes
awln-temporal Oct 29, 2025
561c911
Fix unit test expectations
awln-temporal Oct 29, 2025
d482d91
Address remaining comments
awln-temporal Oct 29, 2025
f8aea8b
Update TODO message
awln-temporal Oct 30, 2025
99328af
Update library search attributes option
awln-temporal Oct 30, 2025
f5eb991
Update panic message format chasm/registrable_component.go
awln-temporal Oct 30, 2025
7c936e3
Update panic message format chasm/registrable_component.go
awln-temporal Oct 30, 2025
6d683fe
Update invalid argument message chasm/visibility.go
awln-temporal Oct 30, 2025
3501cb5
Update invalid argument message chasm/visibility.go
awln-temporal Oct 30, 2025
05d9d12
Address PR comments
awln-temporal Oct 30, 2025
b55c253
Merge branch 'main' into CHASMSearchAttributeComponents
awln-temporal Oct 31, 2025
d25f0dc
Add predefined search attributes
awln-temporal Oct 31, 2025
6269b51
Update error message chasm/visibility.go
awln-temporal Oct 31, 2025
0d1575a
Update error message
awln-temporal Oct 31, 2025
27658af
Merge branch 'main' into CHASMSearchAttributeComponents
awln-temporal Oct 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion chasm/lib/tests/library.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ func (l *library) Name() string {

func (l *library) Components() []*chasm.RegistrableComponent {
return []*chasm.RegistrableComponent{
chasm.NewRegistrableComponent[*PayloadStore]("payloadStore"),
chasm.NewRegistrableComponent[*PayloadStore]("payloadStore",
chasm.WithSearchAttributes(TestKeywordSearchAttribute)),
}
}

Expand Down
12 changes: 6 additions & 6 deletions chasm/lib/tests/payload.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ const (
)

var (
TestKeywordSearchAttribute = chasm.NewSearchAttributeKeyword(TestKeywordSAFieldName, chasm.SearchAttributeFieldKeyword01)

_ chasm.VisibilitySearchAttributesProvider = (*PayloadStore)(nil)
_ chasm.VisibilityMemoProvider = (*PayloadStore)(nil)
)
Expand Down Expand Up @@ -147,12 +149,10 @@ func (s *PayloadStore) LifecycleState(

// SearchAttributes implements chasm.VisibilitySearchAttributesProvider interface
func (s *PayloadStore) SearchAttributes(
_ chasm.Context,
) map[string]chasm.VisibilityValue {
// TODO: UpsertSearchAttribute as well when CHASM framework supports Per-Component SearchAttributes
// For now, we just update a random existing pre-defined SA to make sure the logic works.
return map[string]chasm.VisibilityValue{
TestKeywordSAFieldName: chasm.VisibilityValueString(TestKeywordSAFieldValue),
ctx chasm.Context,
) []chasm.SearchAttributeKeyValue {
return []chasm.SearchAttributeKeyValue{
TestKeywordSearchAttribute.Value(TestKeywordSAFieldValue),
}
}

Expand Down
71 changes: 71 additions & 0 deletions chasm/registrable_component.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package chasm

import (
"fmt"
"reflect"

enumspb "go.temporal.io/api/enums/v1"
"go.temporal.io/api/serviceerror"
)

var _ VisibilitySearchAttributesMapper = (*RegistrableComponent)(nil)

type (
RegistrableComponent struct {
componentType string
Expand All @@ -13,6 +19,11 @@ type (
ephemeral bool
singleCluster bool
shardingFn func(EntityKey) string

// Search attribute mappings
aliasToField map[string]string
fieldToAlias map[string]string
saTypeMap map[string]enumspb.IndexedValueType
}

RegistrableComponentOption func(*RegistrableComponent)
Expand Down Expand Up @@ -56,6 +67,44 @@ func WithShardingFn(
}
}

func WithSearchAttributes(
searchAttributes ...SearchAttribute,
) RegistrableComponentOption {
return func(rc *RegistrableComponent) {
if len(searchAttributes) == 0 {
return
}
rc.aliasToField = make(map[string]string, len(searchAttributes))
rc.fieldToAlias = make(map[string]string, len(searchAttributes))
rc.saTypeMap = make(map[string]enumspb.IndexedValueType, len(searchAttributes))

for _, sa := range searchAttributes {
alias := sa.definition().Alias
field := sa.definition().Field
valueType := sa.definition().ValueType

rc.aliasToField[alias] = field
rc.fieldToAlias[field] = alias
rc.saTypeMap[field] = valueType
}
}
}

// validate checks for errors in the component configuration.
func (rc *RegistrableComponent) validate() error {
// Check for duplicate field names in search attributes
fieldToAliases := make(map[string][]string)
for alias, field := range rc.aliasToField {
fieldToAliases[field] = append(fieldToAliases[field], alias)
}
for field, aliases := range fieldToAliases {
if len(aliases) > 1 {
return fmt.Errorf("search attributes contain duplicate field names: field '%s' is used by multiple aliases: %v", field, aliases)
}
}
return nil
}

// fqType returns the fully qualified name of the component, which is a combination of
// the library name and the component type. This is used to uniquely identify
// the component in the registry.
Expand All @@ -66,3 +115,25 @@ func (rc RegistrableComponent) fqType() string {
}
return fullyQualifiedName(rc.library.Name(), rc.componentType)
}

// SearchAttributeAlias returns the search attribute alias for the given field name.
func (rc *RegistrableComponent) SearchAttributeAlias(field string) (string, error) {
alias, ok := rc.fieldToAlias[field]
if !ok {
return "", serviceerror.NewInvalidArgument(
fmt.Sprintf("registrable component name %s has no alias defined for field name %s", rc.fqType(), field),
)
}
return alias, nil
}

// SearchAttributeField returns the search attribute field name for the given alias.
func (rc *RegistrableComponent) SearchAttributeField(alias string) (string, error) {
field, ok := rc.aliasToField[alias]
if !ok {
return "", serviceerror.NewInvalidArgument(
fmt.Sprintf("registrable component name %s has no field defined for alias name %s", rc.fqType(), alias),
)
}
return field, nil
}
3 changes: 3 additions & 0 deletions chasm/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ func (r *Registry) registerComponent(
if err := r.validateName(rc.componentType); err != nil {
return err
}
if err := rc.validate(); err != nil {
return err
}
fqn := fullyQualifiedName(lib.Name(), rc.componentType)
if _, ok := r.componentByType[fqn]; ok {
return fmt.Errorf("component %s is already registered", fqn)
Expand Down
Loading
Loading