github.com/Jeffail/benthos/v3@v3.65.0/public/bloblang/executor.go (about)

     1  package bloblang
     2  
     3  import (
     4  	"errors"
     5  
     6  	"github.com/Jeffail/benthos/v3/internal/bloblang/mapping"
     7  	"github.com/Jeffail/benthos/v3/internal/bloblang/query"
     8  	"github.com/Jeffail/benthos/v3/lib/message"
     9  	"github.com/Jeffail/benthos/v3/lib/types"
    10  )
    11  
    12  // Executor stores a parsed Bloblang mapping and provides APIs for executing it.
    13  type Executor struct {
    14  	exec              *mapping.Executor
    15  	emptyQueryMessage types.Message
    16  }
    17  
    18  func newExecutor(exec *mapping.Executor) *Executor {
    19  	return &Executor{
    20  		exec:              exec,
    21  		emptyQueryMessage: message.New(nil),
    22  	}
    23  }
    24  
    25  // ErrRootDeleted is returned by a Bloblang query when the mapping results in
    26  // the root being deleted. It might be considered correct to do this in
    27  // situations where filtering is allowed or expected.
    28  var ErrRootDeleted = errors.New("root was deleted")
    29  
    30  // Query executes a Bloblang mapping against a value and returns the result. The
    31  // argument and return values can be structured using the same
    32  // map[string]interface{} and []interface{} types as would be returned by the Go
    33  // standard json package unmarshaler.
    34  //
    35  // If the mapping results in the root of the new document being deleted then
    36  // ErrRootDeleted is returned, which can be used as a signal to filter rather
    37  // than fail the mapping.
    38  func (e *Executor) Query(value interface{}) (interface{}, error) {
    39  	res, err := e.exec.Exec(query.FunctionContext{
    40  		Maps:     e.exec.Maps(),
    41  		Vars:     map[string]interface{}{},
    42  		Index:    0,
    43  		MsgBatch: e.emptyQueryMessage,
    44  	}.WithValue(value))
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  
    49  	switch res.(type) {
    50  	case query.Delete:
    51  		return nil, ErrRootDeleted
    52  	case query.Nothing:
    53  		return value, nil
    54  	}
    55  	return res, nil
    56  }
    57  
    58  // Overlay executes a Bloblang mapping against a value, where assignments are
    59  // overlayed onto an existing structure.
    60  //
    61  // If the mapping results in the root of the new document being deleted then
    62  // ErrRootDeleted is returned, which can be used as a signal to filter rather
    63  // than fail the mapping.
    64  func (e *Executor) Overlay(value interface{}, onto *interface{}) error {
    65  	vars := map[string]interface{}{}
    66  
    67  	if err := e.exec.ExecOnto(query.FunctionContext{
    68  		Maps:     e.exec.Maps(),
    69  		Vars:     vars,
    70  		Index:    0,
    71  		MsgBatch: e.emptyQueryMessage,
    72  	}.WithValue(value), mapping.AssignmentContext{
    73  		Vars:  vars,
    74  		Value: onto,
    75  	}); err != nil {
    76  		return err
    77  	}
    78  
    79  	switch (*onto).(type) {
    80  	case query.Delete:
    81  		return ErrRootDeleted
    82  	case query.Nothing:
    83  		*onto = nil
    84  	}
    85  	return nil
    86  }