Skip to content

Commit 1f3e1eb

Browse files
fix: make dep type dynamic
1 parent b6142af commit 1f3e1eb

File tree

4 files changed

+43
-13
lines changed

4 files changed

+43
-13
lines changed

operations/operation.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ func (o *Operation[IN, OUT, DEP]) Description() string {
6767
return o.def.Description
6868
}
6969

70+
// Def returns the operation definition.
71+
func (o *Operation[IN, OUT, DEP]) Def() Definition {
72+
return o.def
73+
}
74+
7075
// execute runs the operation by calling the OperationHandler.
7176
func (o *Operation[IN, OUT, DEP]) execute(b Bundle, deps DEP, input IN) (output OUT, err error) {
7277
b.Logger.Infow("Executing operation",
@@ -78,14 +83,14 @@ func (o *Operation[IN, OUT, DEP]) execute(b Bundle, deps DEP, input IN) (output
7883
// AsUntyped converts the operation to an untyped operation.
7984
// This is useful for storing operations in a slice or passing them around without type constraints.
8085
// Warning: The input and output types will be converted to `any`, so type safety is lost.
81-
func (o *Operation[IN, OUT, DEP]) AsUntyped() *Operation[any, any, DEP] {
82-
return &Operation[any, any, DEP]{
86+
func (o *Operation[IN, OUT, DEP]) AsUntyped() *Operation[any, any, any] {
87+
return &Operation[any, any, any]{
8388
def: Definition{
8489
ID: o.def.ID,
8590
Version: o.def.Version,
8691
Description: o.def.Description,
8792
},
88-
handler: func(b Bundle, deps DEP, input any) (any, error) {
93+
handler: func(b Bundle, deps any, input any) (any, error) {
8994
var typedInput IN
9095
if input != nil {
9196
var ok bool
@@ -94,7 +99,15 @@ func (o *Operation[IN, OUT, DEP]) AsUntyped() *Operation[any, any, DEP] {
9499
}
95100
}
96101

97-
return o.execute(b, deps, typedInput)
102+
var typedDeps DEP
103+
if deps != nil {
104+
var ok bool
105+
if typedDeps, ok = deps.(DEP); !ok {
106+
return nil, errors.New("dependencies type mismatch")
107+
}
108+
}
109+
110+
return o.execute(b, typedDeps, typedInput)
98111
},
99112
}
100113
}

operations/operation_test.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ func Test_NewOperation(t *testing.T) {
3232
assert.Equal(t, "sum", op.ID())
3333
assert.Equal(t, version.String(), op.Version())
3434
assert.Equal(t, description, op.Description())
35+
assert.Equal(t, op.def, op.Def())
3536
res, err := op.handler(Bundle{}, OpDeps{}, OpInput{1, 2})
3637
require.NoError(t, err)
3738
assert.Equal(t, 3, res)
@@ -106,7 +107,7 @@ func Test_Operation_AsUntyped(t *testing.T) {
106107
// Table-driven test cases
107108
tests := []struct {
108109
name string
109-
deps OpDeps
110+
deps any
110111
input any
111112
wantResult any
112113
wantErr bool
@@ -126,6 +127,13 @@ func Test_Operation_AsUntyped(t *testing.T) {
126127
wantErr: true,
127128
errContains: "input type mismatch",
128129
},
130+
{
131+
name: "invalid dependencies type",
132+
deps: "invalid",
133+
input: OpInput{A: 1, B: 2},
134+
wantErr: true,
135+
errContains: "dependencies type mismatch",
136+
},
129137
}
130138

131139
for _, tt := range tests {

operations/registry.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,26 @@ package operations
33
import "errors"
44

55
// OperationRegistry is a store for operations that allows retrieval based on their definitions.
6-
type OperationRegistry[DEP any] struct {
7-
Ops []*Operation[any, any, DEP]
6+
type OperationRegistry struct {
7+
Ops []*Operation[any, any, any]
88
}
99

1010
// NewOperationRegistry creates a new OperationRegistry with the provided untyped operations.
11-
func NewOperationRegistry[DEP any](ops ...*Operation[any, any, DEP]) OperationRegistry[DEP] {
12-
return OperationRegistry[DEP]{
11+
func NewOperationRegistry(ops ...*Operation[any, any, any]) OperationRegistry {
12+
return OperationRegistry{
1313
Ops: ops,
1414
}
1515
}
1616

1717
// Retrieve retrieves an operation from the store based on its definition.
1818
// It returns an error if the operation is not found.
1919
// The definition must match the operation's ID and version.
20-
func (s OperationRegistry[DEP]) Retrieve(def Definition) (*Operation[any, any, DEP], error) {
20+
func (s OperationRegistry) Retrieve(def Definition) (*Operation[any, any, any], error) {
2121
for _, op := range s.Ops {
2222
if op.ID() == def.ID && op.Version() == def.Version.String() {
2323
return op, nil
2424
}
2525
}
26+
2627
return nil, errors.New("operation not found in registry")
2728
}

operations/registry_test.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,15 @@ import (
1414
// ExampleOperationRegistry demonstrates how to create and use an OperationRegistry
1515
// with operations being executed dynamically with different input/output types.
1616
func ExampleOperationRegistry() {
17+
type Deps1 struct{}
18+
type Deps2 struct{}
19+
1720
// Create operations with different input/output types
1821
stringOp := NewOperation(
1922
"string-op",
2023
semver.MustParse("1.0.0"),
2124
"Echo string operation",
22-
func(e Bundle, deps OpDeps, input string) (string, error) {
25+
func(e Bundle, deps Deps1, input string) (string, error) {
2326
return input, nil
2427
},
2528
)
@@ -28,7 +31,7 @@ func ExampleOperationRegistry() {
2831
"int-op",
2932
semver.MustParse("1.0.0"),
3033
"Echo integer operation",
31-
func(e Bundle, deps OpDeps, input int) (int, error) {
34+
func(e Bundle, deps Deps2, input int) (int, error) {
3235
return input, nil
3336
},
3437
)
@@ -39,6 +42,7 @@ func ExampleOperationRegistry() {
3942
b := NewBundle(context.Background, logger.Nop(), NewMemoryReporter())
4043

4144
inputs := []any{"input1", 42}
45+
deps := []any{Deps1{}, Deps2{}}
4246
defs := []Definition{
4347
{ID: "string-op", Version: semver.MustParse("1.0.0")},
4448
{ID: "int-op", Version: semver.MustParse("1.0.0")},
@@ -52,7 +56,11 @@ func ExampleOperationRegistry() {
5256
continue
5357
}
5458

55-
report, err := ExecuteOperation(b, retrievedOp, OpDeps{}, inputs[i])
59+
report, err := ExecuteOperation(b, retrievedOp, deps[i], inputs[i])
60+
if err != nil {
61+
fmt.Println("error executing operation:", err)
62+
continue
63+
}
5664

5765
fmt.Println("operation output:", report.Output)
5866
}

0 commit comments

Comments
 (0)