data

package
v0.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 7, 2025 License: Apache-2.0 Imports: 8 Imported by: 0

README

Data Management in go-polyscript

This package handles the flow of data to and from script evaluations in go-polyscript. It defines how data is stored, accessed, and passed between Go and script environments.

Key Concepts

Types of Data

There are two main types of data in go-polyscript:

  1. Static Data:

    • Defined once at script compile/load time
    • Remains constant for all executions of a compiled script
    • Often contains configuration values, utility functions, or constants
    • Provided via StaticProvider and accessed directly at the top level of the ctx variable
  2. Dynamic Data:

    • Provided fresh for each script execution
    • Contains runtime-specific data like request parameters, user inputs, etc.
    • Changes between different executions of the same script
    • Added to the context via AddDataToContext method
    • Stored directly at the root level of the context

Both types of data are made available to scripts as part of the top-level ctx variable, which is injected into the script's global scope.

Data Flow
┌───────────────────┐    ┌───────────────────┐    ┌───────────────────┐
│   Static Data     │    │   Dynamic Data    │    │     Provider      │
│                   │    │                   │    │                   │
│                   │    │                   │    │ GetData()         │
│ - Config values   │    │ - Request params  │    │ AddDataToContext()│
│ - Constants       │    │ - User inputs     │    │                   │
└─────────┬─────────┘    └─────────┬─────────┘    └─────────┬─────────┘
          │                        │                        │
          │                        │                        │
          ▼                        ▼                        ▼
┌─────────────────────────────────────────────────────────────────────┐
│                          Context                                    │
│                                                                     │
│  Data stored under constants.EvalData key with structure:           │
│  {                                                                  │
│    // All data is at the top level of the context                   │
│    "config_value1": ...,   // Static data (from StaticProvider)     │
│    "config_value2": ...,   // Static data (from StaticProvider)     │
│    "user_data": ...,       // Dynamic data (user-provided)          │
│    "request": { ... },     // HTTP request data (if available)      │
│  }                                                                  │
└─────────────────────────────────────┬───────────────────────────────┘
                                      │
                                      ▼
┌─────────────────────────────────────────────────────────────────────┐
│                        VM Execution                                 │
│                                                                     │
│  - VM implementations access data through the Provider interface    │
│  - Each VM makes the data available as a global `ctx` variable      │
│                                                                     │
│  Script accesses via top-level `ctx` variable:                      │
│    ctx["config_value1"]             // Static data                  │
│    ctx["user_data"]                 // Dynamic data                 │
│    ctx["request"]["Method"]         // HTTP request data            │
└─────────────────────────────────────────────────────────────────────┘

Data Access Patterns in Scripts

Scripts access all data directly from the top level of the context:

// Static configuration
config := ctx["config_name"]

// Dynamic user data
userData := ctx["user_data"]

// HTTP request data
requestMethod := ctx["request"]["Method"]
urlPath := ctx["request"]["URL_Path"]
requestBody := ctx["request"]["Body"]

When providing data to scripts, use explicit keys in your data maps for clarity:

// Add HTTP request data with explicit key
enrichedCtx, _ := evaluator.AddDataToContext(ctx, map[string]any{
    "request": httpRequest
})

Providers

Providers control how data is stored and accessed for script execution:

  • StaticProvider: Returns predefined data, useful for configuration and static values
  • ContextProvider: Used for storing and retrieving thread-safe dynamic runtime data
  • CompositeProvider: Chains multiple providers, combining static and dynamic data sources

A common pattern is to combine a StaticProvider for configuration with a ContextProvider for runtime data:

// Static configuration values
staticProvider := data.NewStaticProvider(map[string]any{
    "config": "value",
})

// Runtime data provider for thread-safe per-request data
ctxProvider := data.NewContextProvider(constants.EvalData)

// Combine them for unified access
compositeProvider := data.NewCompositeProvider(staticProvider, ctxProvider)

Data Preparation and Evaluation

The AddDataToContext method (defined in the data.Setter interface) allows for a separation between:

  1. Preparing the data and enriching the context
  2. Evaluating the script with the prepared context

This pattern enables distributed architectures where:

  • Data preparation occurs on one system (e.g., web server)
  • Evaluation occurs on another system (e.g., worker node)

Best Practices

  1. Use a ContextProvider with the constants.EvalData key for dynamic request-specific data
  2. Use a StaticProvider for configuration and other static data
  3. Use CompositeProvider when you need to combine static and dynamic data sources
  4. Always use explicit keys when adding data with AddDataToContext(ctx, map[string]any{"key": value})
  5. For HTTP requests, wrap them with a descriptive key: map[string]any{"request": httpRequest}

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrStaticProviderNoRuntimeUpdates = errors.New(
	"StaticProvider doesn't support adding data at runtime",
)

ErrStaticProviderNoRuntimeUpdates is returned when trying to add runtime data to a StaticProvider. This is a sentinel error that can be checked by CompositeProvider to handle gracefully.

Functions

func AddDataToContextHelper

func AddDataToContextHelper(
	ctx context.Context,
	logger *slog.Logger,
	provider Provider,
	d ...map[string]any,
) (context.Context, error)

AddDataToContextHelper is a utility function that implements the common logic for adding data to a context for evaluation. This function is used by various engine implementations to maintain consistent data handling behavior.

Parameters:

  • ctx: The base context to enrich
  • logger: A logger instance for recording operations
  • provider: The data provider to use for storing data
  • d: Variable list of data items to add to the context

Returns:

  • enrichedCtx: The context with added data
  • err: Any error encountered during the operation

Types

type CompositeProvider

type CompositeProvider struct {
	// contains filtered or unexported fields
}

CompositeProvider combines multiple providers, with later providers overriding values from earlier ones in the chain.

func NewCompositeProvider

func NewCompositeProvider(providers ...Provider) *CompositeProvider

NewCompositeProvider creates a provider that queries given providers in order.

func (*CompositeProvider) AddDataToContext

func (p *CompositeProvider) AddDataToContext(
	ctx context.Context,
	data ...map[string]any,
) (context.Context, error)

AddDataToContext distributes data to all providers in the chain. Continues through all providers even if some fail. StaticProvider errors are handled specially based on context.

Example:

ctx := context.Background()
staticProvider := NewStaticProvider(map[string]any{"config": configData})
contextProvider := NewContextProvider(constants.EvalData)
composite := NewCompositeProvider(staticProvider, contextProvider)
ctx, err := composite.AddDataToContext(ctx, req, userData)

func (*CompositeProvider) GetData

func (p *CompositeProvider) GetData(ctx context.Context) (map[string]any, error)

GetData retrieves data from all providers and merges them into a single map. Queries providers in sequence, with later providers overriding values from earlier ones. Performs deep merging of nested maps for proper data composition. Returns error on first provider failure.

type ContextProvider

type ContextProvider struct {
	// contains filtered or unexported fields
}

ContextProvider retrieves and stores data in the context using a specified key.

func NewContextProvider

func NewContextProvider(contextKey constants.ContextKey) *ContextProvider

NewContextProvider creates a new ContextProvider with the given context key. The context key determines where data is stored in the context object.

See README.md for usage examples.

func (*ContextProvider) AddDataToContext

func (p *ContextProvider) AddDataToContext(
	ctx context.Context,
	data ...map[string]any,
) (context.Context, error)

AddDataToContext merges the provided maps into the context. Maps are recursively merged, HTTP Request objects are converted to maps, and later values override earlier ones for duplicate keys.

See README.md for detailed usage examples.

func (*ContextProvider) GetData

func (p *ContextProvider) GetData(ctx context.Context) (map[string]any, error)

GetData extracts data from the context using the configured context key.

type Getter

type Getter interface {
	GetData(ctx context.Context) (map[string]any, error)
}

Getter defines the interface for retrieving data from a context.

type Provider

type Provider interface {
	// Getter retrieves associated data from a context during script eval.
	Getter

	// Setter enriches a context with a link to data, allowing the script
	// to access it using the ExecutableUnit's DataProvider.
	Setter
}

Provider defines the interface for accessing runtime data for script execution.

type Setter

type Setter interface {
	// AddDataToContext enriches a context with data for script evaluation.
	// It processes input data according to the engine implementation and stores it
	// in the context using the ExecutableUnit's DataProvider.
	//
	// The variadic data parameter accepts maps with string keys and arbitrary values.
	// HTTP requests, structs, and other types should be wrapped in maps with descriptive keys.
	//
	// Example:
	//  scriptData := map[string]any{"greeting": "Hello, World!"}
	//  enrichedCtx, err := evaluator.AddDataToContext(ctx, map[string]any{"request": request}, scriptData)
	//  if err != nil {
	//      return err
	//  }
	//  result, err := evaluator.Eval(enrichedCtx)
	AddDataToContext(ctx context.Context, data ...map[string]any) (context.Context, error)
}

Setter prepares data for script evaluation by enriching a context. This interface supports separating data preparation from evaluation, enabling distributed architectures where these steps can occur on different systems.

type StaticProvider

type StaticProvider struct {
	// contains filtered or unexported fields
}

StaticProvider supplies a predefined map of data. Useful for configuration values and testing.

func NewStaticProvider

func NewStaticProvider(data map[string]any) *StaticProvider

NewStaticProvider creates a provider with fixed data. Initializes with an empty map if nil is provided.

func (*StaticProvider) AddDataToContext

func (p *StaticProvider) AddDataToContext(
	ctx context.Context,
	_ ...map[string]any,
) (context.Context, error)

AddDataToContext returns a sentinel error as StaticProvider doesn't support dynamic data. Use a ContextProvider or CompositeProvider when runtime data updates are needed. The CompositeProvider should check for this specific error using errors.Is.

func (*StaticProvider) GetData

func (p *StaticProvider) GetData(_ context.Context) (map[string]any, error)

GetData returns the static data map, cloned to prevent modification.

type Types

type Types string

Types of an object as a string.

const (
	BOOL     Types = "bool"
	ERROR    Types = "error"
	FUNCTION Types = "function"
	INT      Types = "int"
	MAP      Types = "map"
	STRING   Types = "string"
	NONE     Types = "none"
	FLOAT    Types = "float"
	LIST     Types = "list"
	TUPLE    Types = "tuple"
	SET      Types = "set"
)

These valid types as constants, limited for our use.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL