Skip to content

Commit 7b96377

Browse files
committed
wip interfaces
1 parent 0700203 commit 7b96377

File tree

2 files changed

+98
-7
lines changed

2 files changed

+98
-7
lines changed

dbos/serialization_test.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,26 @@ type TestWorkflowData struct {
371371
Metadata map[string]string
372372
}
373373

374+
// Interface for testing interface-typed workflows
375+
type DataProvider interface {
376+
GetMessage() string
377+
GetValue() int
378+
}
379+
380+
// Concrete implementation of DataProvider
381+
type ConcreteDataProvider struct {
382+
Message string
383+
Value int
384+
}
385+
386+
func (c ConcreteDataProvider) GetMessage() string {
387+
return c.Message
388+
}
389+
390+
func (c ConcreteDataProvider) GetValue() int {
391+
return c.Value
392+
}
393+
374394
// Test workflows and steps
375395
func serializerTestStep(_ context.Context, input TestWorkflowData) (TestWorkflowData, error) {
376396
return input, nil
@@ -397,6 +417,12 @@ func serializerAnyValueWorkflow(ctx DBOSContext, input any) (any, error) {
397417
})
398418
}
399419

420+
func serializerInterfaceValueWorkflow(ctx DBOSContext, input DataProvider) (DataProvider, error) {
421+
return RunAsStep(ctx, func(context context.Context) (DataProvider, error) {
422+
return input, nil
423+
})
424+
}
425+
400426
func serializerErrorStep(_ context.Context, _ TestWorkflowData) (TestWorkflowData, error) {
401427
return TestWorkflowData{}, fmt.Errorf("step error")
402428
}
@@ -546,6 +572,7 @@ func TestSerializer(t *testing.T) {
546572
RegisterWorkflow(executor, serializerSetEventWorkflow)
547573
RegisterWorkflow(executor, serializerGetEventWorkflow)
548574
RegisterWorkflow(executor, serializerRecoveryWorkflow)
575+
RegisterWorkflow(executor, serializerInterfaceValueWorkflow)
549576
if serializerName == "JSON" {
550577
// Cannot register "any" workflow with Gob serializer
551578
RegisterWorkflow(executor, serializerAnyValueWorkflow)
@@ -598,6 +625,68 @@ func TestSerializer(t *testing.T) {
598625
testComprehensiveWorkflowValues(t, executor, handle, input)
599626
})
600627

628+
// Test workflow with interface type
629+
t.Run("ComprehensiveInterfaceValues", func(t *testing.T) {
630+
input := ConcreteDataProvider{
631+
Message: "interface test message",
632+
Value: 123,
633+
}
634+
635+
handle, err := RunWorkflow(executor, serializerInterfaceValueWorkflow, DataProvider(input))
636+
require.NoError(t, err, "Interface workflow execution failed")
637+
638+
// Get the result
639+
result, err := handle.GetResult()
640+
require.NoError(t, err, "Failed to get workflow result")
641+
642+
// For interface types, we need to check the concrete type
643+
concreteResult, ok := result.(ConcreteDataProvider)
644+
require.True(t, ok, "Result should be ConcreteDataProvider type")
645+
assert.Equal(t, input.Message, concreteResult.Message, "Message should match")
646+
assert.Equal(t, input.Value, concreteResult.Value, "Value should match")
647+
648+
// Test with ListWorkflows
649+
workflows, err := ListWorkflows(executor,
650+
WithWorkflowIDs([]string{handle.GetWorkflowID()}),
651+
WithLoadInput(true),
652+
WithLoadOutput(true),
653+
)
654+
require.NoError(t, err, "Failed to list workflows")
655+
require.Len(t, workflows, 1, "Expected 1 workflow")
656+
657+
workflow := workflows[0]
658+
require.NotNil(t, workflow.Input, "Workflow input should not be nil")
659+
require.NotNil(t, workflow.Output, "Workflow output should not be nil")
660+
661+
// For Gob serializer, the concrete type is preserved
662+
// For JSON serializer, we get a map that needs conversion
663+
dbosCtx, ok := executor.(*dbosContext)
664+
require.True(t, ok, "expected dbosContext")
665+
isJSON := isJSONSerializer(dbosCtx.serializer)
666+
667+
if isJSON {
668+
// JSON serializer returns map[string]any
669+
inputMap, ok := workflow.Input.(map[string]any)
670+
require.True(t, ok, "Input should be map[string]any for JSON")
671+
assert.Equal(t, input.Message, inputMap["Message"], "Message should match in input")
672+
assert.Equal(t, float64(input.Value), inputMap["Value"], "Value should match in input")
673+
674+
outputMap, ok := workflow.Output.(map[string]any)
675+
require.True(t, ok, "Output should be map[string]any for JSON")
676+
assert.Equal(t, input.Message, outputMap["Message"], "Message should match in output")
677+
assert.Equal(t, float64(input.Value), outputMap["Value"], "Value should match in output")
678+
} else {
679+
// Gob serializer preserves the concrete type
680+
inputConcrete, ok := workflow.Input.(ConcreteDataProvider)
681+
require.True(t, ok, "Input should be ConcreteDataProvider for Gob")
682+
assert.Equal(t, input, inputConcrete, "Input should match")
683+
684+
outputConcrete, ok := workflow.Output.(ConcreteDataProvider)
685+
require.True(t, ok, "Output should be ConcreteDataProvider for Gob")
686+
assert.Equal(t, input, outputConcrete, "Output should match")
687+
}
688+
})
689+
601690
// Test nil values with pointer type workflow
602691
t.Run("NilValuesPointer", func(t *testing.T) {
603692
handle, err := RunWorkflow(executor, serializerNilValueWorkflow, (*TestWorkflowData)(nil))

dbos/workflow.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,7 +1195,7 @@ func RunAsStep[R any](ctx DBOSContext, fn Step[R], opts ...StepOption) (R, error
11951195
typedResult, err = convertJSONToType[R](result)
11961196
if err != nil {
11971197
workflowID, _ := ctx.GetWorkflowID() // Must be within a workflow so we can ignore the error
1198-
return *new(R), newWorkflowExecutionError(workflowID, fmt.Errorf("converting step result to expected type: %w", err))
1198+
return *new(R), newWorkflowExecutionError(workflowID, fmt.Errorf("converting step result to expected type %T: %w", *new(R), err))
11991199
}
12001200
} else {
12011201
var ok bool
@@ -1355,9 +1355,8 @@ func Send[P any](ctx DBOSContext, destinationID string, message P, topic string)
13551355
logger = c.logger
13561356
serializer = c.serializer
13571357
}
1358-
var typedMessage P
13591358
if isGobSerializer(serializer) {
1360-
safeGobRegister(typedMessage, logger)
1359+
safeGobRegister(message, logger)
13611360
}
13621361
return ctx.Send(ctx, destinationID, message, topic)
13631362
}
@@ -1455,9 +1454,8 @@ func SetEvent[P any](ctx DBOSContext, key string, message P) error {
14551454
logger = c.logger
14561455
serializer = c.serializer
14571456
}
1458-
var typedMessage P
14591457
if isGobSerializer(serializer) {
1460-
safeGobRegister(typedMessage, logger)
1458+
safeGobRegister(message, logger)
14611459
}
14621460
return ctx.SetEvent(ctx, key, message)
14631461
}
@@ -1505,9 +1503,13 @@ func GetEvent[R any](ctx DBOSContext, targetWorkflowID, key string, timeout time
15051503
return *new(R), nil
15061504
}
15071505

1508-
// JSON serializer loses type information - convert back to expected type
1506+
var serializer Serializer
1507+
if dbosCtx, ok := ctx.(*dbosContext); ok {
1508+
serializer = dbosCtx.serializer
1509+
}
15091510
var typedValue R
1510-
if dbosCtx, ok := ctx.(*dbosContext); ok && isJSONSerializer(dbosCtx.serializer) {
1511+
// JSON serializer loses type information - convert back to expected type
1512+
if isJSONSerializer(serializer) {
15111513
typedValue, err = convertJSONToType[R](value)
15121514
if err != nil {
15131515
return *new(R), fmt.Errorf("converting event value to type %T: %w", *new(R), err)

0 commit comments

Comments
 (0)