Skip to content

Commit d097a06

Browse files
committed
change PrepareContext to AddDataToContext, and update the interface for sending data through to the data.Provider
1 parent bf45b01 commit d097a06

36 files changed

+636
-455
lines changed

README.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ evaluator, _ := polyscript.FromRisorString(script, logHandler)
106106

107107
ctx := context.Background()
108108
runtimeData := map[string]any{"name": "Billie Jean", "relationship": false}
109-
enrichedCtx, _ := evaluator.PrepareContext(ctx, runtimeData)
109+
enrichedCtx, _ := evaluator.AddDataToContext(ctx, runtimeData)
110110

111111
// Execute with the "enriched" context containing the link to the input data
112112
result, _ := evaluator.Eval(enrichedCtx)
@@ -127,14 +127,14 @@ evaluator, _ := polyscript.FromRisorStringWithData(script, staticData, logHandle
127127

128128
// For each request, prepare dynamic data
129129
requestData := map[string]any{"userId": 123}
130-
enrichedCtx, _ := evaluator.PrepareContext(context.Background(), requestData)
130+
enrichedCtx, _ := evaluator.AddDataToContext(context.Background(), requestData)
131131

132132
// Execute with both static and dynamic data available
133133
result, _ := evaluator.Eval(enrichedCtx)
134134

135-
// In scripts, data can be accessed from both locations:
136-
// appName := ctx["appName"] // Static data: "MyApp"
137-
// userId := ctx["input_data"]["userId"] // Dynamic data: 123
135+
// In scripts, all data is accessed from the context:
136+
// appName := ctx["appName"] // From static data: "MyApp"
137+
// userId := ctx["userId"] // From dynamic data: 123
138138
```
139139

140140
## Architecture
@@ -151,11 +151,13 @@ go-polyscript is structured around a few key concepts:
151151

152152
### Note on Data Access Patterns
153153

154-
go-polyscript uses a unified `Provider` interface to supply data to scripts. The library has standardized on storing dynamic runtime data under the `input_data` key (previously `script_data`). For maximum compatibility, scripts should handle two data access patterns:
154+
go-polyscript uses a two-layer approach for handling data:
155155

156-
1. Top-level access for static data: `ctx["config_value"]`
157-
2. Nested access for dynamic data: `ctx["input_data"]["user_data"]`
158-
3. HTTP request data access: `ctx["input_data"]["request"]["method"]` (request objects are always stored under input_data)
156+
1. **Data Provider Layer**: The `Provider` interface (via `AddDataToContext`) handles storage mechanisms and general type conversions. This layer is pluggable, allowing data to be stored in various backends while maintaining a consistent API.
157+
158+
2. **Engine-Specific Layer**: Each engine's `Evaluator` implementation handles the engine-specific conversions between the stored data and the format required by that particular scripting engine.
159+
160+
This separation allows scripts to access data with consistent patterns regardless of the storage mechanism or script engine. For example, data you store with `{"config": value}` will be accessible in your scripts as `ctx["config"]`, with each engine handling the specific conversions needed for its runtime.
159161

160162
See the [Data Providers](#working-with-data-providers) section for more details.
161163

engines/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ This package contains virtual machine implementations for executing scripts in v
3232

3333
4. **Data Preparation Stage**
3434
- This phase is optional, and must happen prior to evaluation when runtime input data is used
35-
- The `Evaluator` implements the `evaluationEvaluator` interface, which has a `PrepareContext` method
36-
- The `PrepareContext` method takes a `context.Context` and a variadic list of `any`
37-
- `PrepareContext` calls the `data.Provider` to convert and store the data, somewhere accessible to the Evaluator
35+
- The `Evaluator` implements the `data.Setter` interface, which has an `AddDataToContext` method
36+
- The `AddDataToContext` method takes a `context.Context` and a variadic list of `map[string]any`
37+
- `AddDataToContext` calls the `data.Provider` to store the data, somewhere accessible to the Evaluator
3838
- The conversion is fairly opinionated, and handled by the `data.Provider`
3939
- For example, it converts an `http.Request` into a `map[string]any` using the schema in `helper.RequestToMap`
40-
- The `PrepareContext` method returns a new context with the data stored or linked in it
40+
- The `AddDataToContext` method returns a new context with the data stored or linked in it
4141

4242
5. **Execution Stage**
4343
- When `Eval(ctx)` is called, the `data.Provider` first loads the input data into the VM

engines/TESTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ This document outlines standardized testing principles for go-polyscript to ensu
3636
| Options | `TestCompilerOptions` |
3737
| Executables | `TestExecutable` |
3838
| Evaluator execution | `TestEvaluator_Evaluate` |
39-
| Context preparation | `TestEvaluator_PrepareContext` |
39+
| Context preparation | `TestEvaluator_AddDataToContext` |
4040
| Response handling | `TestResponseMethods` |
4141
| Type conversion | `TestToGoType` / `TestToMachineType` |
4242

engines/benchmarks/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ For distributed architectures, separate data preparation from evaluation to impr
2424

2525
```go
2626
// PREPARE DATA (can happen on system A)
27-
enrichedCtx, _ := evaluator.PrepareContext(ctx, inputData)
27+
enrichedCtx, _ := evaluator.AddDataToContext(ctx, inputData)
2828

2929
// EVALUATE (can happen on system B)
3030
result, _ := evaluator.Eval(enrichedCtx)

engines/benchmarks/benchmark_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,9 @@ func BenchmarkDataProviders(b *testing.B) {
166166

167167
b.Run("CompositeProvider", func(b *testing.B) {
168168
// For CompositeProvider use case, we can prepare the context separately
169-
// We need a special script that accesses the name via input_data
169+
// We access the name directly from the context
170170
compositeScript := `
171-
name := ctx["input_data"]["name"]
171+
name := ctx["name"]
172172
message := "Hello, " + name + "!"
173173
{
174174
"greeting": message,
@@ -186,8 +186,8 @@ func BenchmarkDataProviders(b *testing.B) {
186186
}
187187

188188
ctx := context.Background()
189-
// Use PrepareContext to add the dynamic part
190-
ctx, err = evaluator.PrepareContext(ctx, inputData)
189+
// Use AddDataToContext to add the dynamic part
190+
ctx, err = evaluator.AddDataToContext(ctx, map[string]any{"name": "World"})
191191
if err != nil {
192192
b.Fatalf("Failed to prepare context: %v", err)
193193
}

engines/extism/evaluator/evaluator.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -208,21 +208,21 @@ func (be *Evaluator) Eval(ctx context.Context) (platform.EvaluatorResponse, erro
208208
return result, nil
209209
}
210210

211-
// PrepareContext implements the EvalDataPreparer interface for Extism WebAssembly modules.
211+
// AddDataToContext implements the data.Setter interface for Extism WebAssembly modules.
212212
// It enriches the provided context with data for script evaluation, using the
213213
// ExecutableUnit's DataProvider to store the data.
214-
func (be *Evaluator) PrepareContext(
214+
func (be *Evaluator) AddDataToContext(
215215
ctx context.Context,
216-
d ...any,
216+
d ...map[string]any,
217217
) (context.Context, error) {
218-
logger := be.logger.WithGroup("PrepareContext")
218+
logger := be.logger.WithGroup("AddDataToContext")
219219

220220
// Use the shared helper function for context preparation
221221
if be.execUnit == nil || be.execUnit.GetDataProvider() == nil {
222222
return ctx, fmt.Errorf("no data provider available")
223223
}
224224

225-
return data.PrepareContextHelper(
225+
return data.AddDataToContextHelper(
226226
ctx,
227227
logger,
228228
be.execUnit.GetDataProvider(),

engines/extism/evaluator/evaluator_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func (m *mockErrProvider) GetData(ctx context.Context) (map[string]any, error) {
6161

6262
func (m *mockErrProvider) AddDataToContext(
6363
ctx context.Context,
64-
data ...any,
64+
data ...map[string]any,
6565
) (context.Context, error) {
6666
return ctx, m.err
6767
}
@@ -607,14 +607,14 @@ func TestEvaluator_Evaluate(t *testing.T) {
607607
})
608608
}
609609

610-
// TestEvaluator_PrepareContext tests the PrepareContext method with various scenarios
611-
func TestEvaluator_PrepareContext(t *testing.T) {
610+
// TestEvaluator_AddDataToContext tests the AddDataToContext method with various scenarios
611+
func TestEvaluator_AddDataToContext(t *testing.T) {
612612
t.Parallel()
613613

614614
tests := []struct {
615615
name string
616616
setupExe func(t *testing.T) *script.ExecutableUnit
617-
inputs []any
617+
inputs []map[string]any
618618
wantError bool
619619
expectedErr string
620620
}{
@@ -633,7 +633,7 @@ func TestEvaluator_PrepareContext(t *testing.T) {
633633
Content: content,
634634
}
635635
},
636-
inputs: []any{map[string]any{"test": "data"}},
636+
inputs: []map[string]any{{"test": "data"}},
637637
wantError: true,
638638
expectedErr: "no data provider available",
639639
},
@@ -652,7 +652,7 @@ func TestEvaluator_PrepareContext(t *testing.T) {
652652
Content: content,
653653
}
654654
},
655-
inputs: []any{map[string]any{"test": "data"}},
655+
inputs: []map[string]any{{"test": "data"}},
656656
wantError: false,
657657
},
658658
{
@@ -670,7 +670,7 @@ func TestEvaluator_PrepareContext(t *testing.T) {
670670
Content: content,
671671
}
672672
},
673-
inputs: []any{},
673+
inputs: []map[string]any{{}},
674674
wantError: false,
675675
},
676676
{
@@ -679,7 +679,7 @@ func TestEvaluator_PrepareContext(t *testing.T) {
679679
t.Helper()
680680
return nil
681681
},
682-
inputs: []any{map[string]any{"test": "data"}},
682+
inputs: []map[string]any{{"test": "data"}},
683683
wantError: true,
684684
expectedErr: "no data provider available",
685685
},
@@ -701,7 +701,7 @@ func TestEvaluator_PrepareContext(t *testing.T) {
701701
Content: content,
702702
}
703703
},
704-
inputs: []any{map[string]any{"test": "data"}},
704+
inputs: []map[string]any{{"test": "data"}},
705705
wantError: true,
706706
expectedErr: "provider error",
707707
},
@@ -714,7 +714,7 @@ func TestEvaluator_PrepareContext(t *testing.T) {
714714
evaluator := New(handler, exe)
715715

716716
ctx := context.Background()
717-
enrichedCtx, err := evaluator.PrepareContext(ctx, tt.inputs...)
717+
enrichedCtx, err := evaluator.AddDataToContext(ctx, tt.inputs...)
718718

719719
// Check error expectations
720720
if tt.wantError {

engines/extism/new.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func FromExtismLoader(
3434
}
3535

3636
// FromExtismLoaderWithData creates an Extism evaluator with both static and dynamic data capabilities.
37-
// To add runtime data, use the `PrepareContext` method on the evaluator to add data to the context.
37+
// To add runtime data, use the `AddDataToContext` method on the evaluator to add data to the context.
3838
//
3939
// Input parameters:
4040
// - l: loader implementation for loading the WASM content

engines/mocks/evaluator.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,11 @@ func (m *Evaluator) Load(newVersion script.ExecutableUnit) error {
3131
return args.Error(0)
3232
}
3333

34-
// PrepareContext is a mock implementation of the PrepareContext method.
35-
func (m *Evaluator) PrepareContext(ctx context.Context, d ...any) (context.Context, error) {
34+
// AddDataToContext is a mock implementation of the AddDataToContext method.
35+
func (m *Evaluator) AddDataToContext(
36+
ctx context.Context,
37+
d ...map[string]any,
38+
) (context.Context, error) {
3639
args := m.Called(ctx, d)
3740
return args.Get(0).(context.Context), args.Error(1)
3841
}

engines/risor/evaluator/evaluator.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -155,21 +155,21 @@ func (be *Evaluator) Eval(ctx context.Context) (platform.EvaluatorResponse, erro
155155
return result, nil
156156
}
157157

158-
// PrepareContext implements the EvalDataPreparer interface for Risor scripts.
158+
// AddDataToContext implements the data.Setter interface for Risor scripts.
159159
// It enriches the provided context with data for script evaluation, using the
160160
// ExecutableUnit's DataProvider to store the data.
161-
func (be *Evaluator) PrepareContext(
161+
func (be *Evaluator) AddDataToContext(
162162
ctx context.Context,
163-
d ...any,
163+
d ...map[string]any,
164164
) (context.Context, error) {
165-
logger := be.logger.WithGroup("PrepareContext")
165+
logger := be.logger.WithGroup("AddDataToContext")
166166

167167
// Use the shared helper function for context preparation
168168
if be.execUnit == nil || be.execUnit.GetDataProvider() == nil {
169169
return ctx, fmt.Errorf("no data provider available")
170170
}
171171

172-
return data.PrepareContextHelper(
172+
return data.AddDataToContextHelper(
173173
ctx,
174174
logger,
175175
be.execUnit.GetDataProvider(),

engines/risor/evaluator/evaluator_test.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ func (m *MockProvider) GetData(ctx context.Context) (map[string]any, error) {
3636
return nil, args.Error(1)
3737
}
3838

39-
func (m *MockProvider) AddDataToContext(ctx context.Context, data ...any) (context.Context, error) {
39+
func (m *MockProvider) AddDataToContext(
40+
ctx context.Context,
41+
data ...map[string]any,
42+
) (context.Context, error) {
4043
args := m.Called(ctx, data)
4144
if ctx, ok := args.Get(0).(context.Context); ok {
4245
return ctx, args.Error(1)
@@ -170,7 +173,6 @@ func TestEvaluator_Evaluate(t *testing.T) {
170173

171174
for _, tt := range tests {
172175
t.Run(tt.name, func(t *testing.T) {
173-
// Set up the environment
174176
handler := slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
175177
Level: slog.LevelDebug,
176178
})
@@ -194,7 +196,7 @@ func TestEvaluator_Evaluate(t *testing.T) {
194196

195197
// Create the context with eval data
196198
evalData := map[string]any{
197-
constants.Request: rMap,
199+
"request": rMap,
198200
}
199201
ctx := context.WithValue(context.Background(), constants.EvalData, evalData)
200202

@@ -456,15 +458,14 @@ func TestEvaluator_Evaluate(t *testing.T) {
456458
})
457459
}
458460

459-
// TestEvaluator_PrepareContext tests the PrepareContext method with various scenarios
460-
func TestEvaluator_PrepareContext(t *testing.T) {
461+
func TestEvaluator_AddDataToContext(t *testing.T) {
461462
t.Parallel()
462463

463464
// The test cases
464465
tests := []struct {
465466
name string
466467
setupExe func(t *testing.T) *script.ExecutableUnit
467-
inputs []any
468+
inputs []map[string]any
468469
wantError bool
469470
errorMessage string
470471
}{
@@ -484,7 +485,7 @@ func TestEvaluator_PrepareContext(t *testing.T) {
484485

485486
return &script.ExecutableUnit{DataProvider: mockProvider}
486487
},
487-
inputs: []any{map[string]any{"test": "data"}},
488+
inputs: []map[string]any{{"test": "data"}},
488489
wantError: false,
489490
},
490491
{
@@ -499,7 +500,7 @@ func TestEvaluator_PrepareContext(t *testing.T) {
499500

500501
return &script.ExecutableUnit{DataProvider: mockProvider}
501502
},
502-
inputs: []any{map[string]any{"test": "data"}},
503+
inputs: []map[string]any{{"test": "data"}},
503504
wantError: true,
504505
errorMessage: "provider error",
505506
},
@@ -509,7 +510,7 @@ func TestEvaluator_PrepareContext(t *testing.T) {
509510
t.Helper()
510511
return &script.ExecutableUnit{DataProvider: nil}
511512
},
512-
inputs: []any{map[string]any{"test": "data"}},
513+
inputs: []map[string]any{{"test": "data"}},
513514
wantError: true,
514515
errorMessage: "no data provider available",
515516
},
@@ -519,7 +520,7 @@ func TestEvaluator_PrepareContext(t *testing.T) {
519520
t.Helper()
520521
return nil
521522
},
522-
inputs: []any{map[string]any{"test": "data"}},
523+
inputs: []map[string]any{{"test": "data"}},
523524
wantError: true,
524525
errorMessage: "no data provider available",
525526
},
@@ -539,7 +540,7 @@ func TestEvaluator_PrepareContext(t *testing.T) {
539540
}
540541

541542
ctx := context.Background()
542-
result, err := evaluator.PrepareContext(ctx, tt.inputs...)
543+
result, err := evaluator.AddDataToContext(ctx, tt.inputs...)
543544

544545
if tt.wantError {
545546
require.Error(t, err)

engines/risor/new.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func FromRisorLoader(
3131
}
3232

3333
// FromRisorLoaderWithData creates a Risor evaluator with both static and dynamic data capabilities.
34-
// To add runtime data, use the `PrepareContext` method on the evaluator to add data to the context.
34+
// To add runtime data, use the `AddDataToContext` method on the evaluator to add data to the context.
3535
//
3636
// Input parameters:
3737
// - logHandler: logger handler for logging

engines/starlark/evaluator/evaluator.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -222,21 +222,21 @@ func (be *Evaluator) Eval(ctx context.Context) (platform.EvaluatorResponse, erro
222222
return result, nil
223223
}
224224

225-
// PrepareContext implements the EvalDataPreparer interface for Starlark scripts.
225+
// AddDataToContext implements the data.Setter interface for Starlark scripts.
226226
// It enriches the provided context with data for script evaluation, using the
227227
// ExecutableUnit's DataProvider to store the data.
228-
func (be *Evaluator) PrepareContext(
228+
func (be *Evaluator) AddDataToContext(
229229
ctx context.Context,
230-
d ...any,
230+
d ...map[string]any,
231231
) (context.Context, error) {
232-
logger := be.logger.WithGroup("PrepareContext")
232+
logger := be.logger.WithGroup("AddDataToContext")
233233

234234
// Use the shared helper function for context preparation
235235
if be.execUnit == nil || be.execUnit.GetDataProvider() == nil {
236236
return ctx, fmt.Errorf("no data provider available")
237237
}
238238

239-
return data.PrepareContextHelper(
239+
return data.AddDataToContextHelper(
240240
ctx,
241241
logger,
242242
be.execUnit.GetDataProvider(),

0 commit comments

Comments
 (0)