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 }