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

     1  package bloblang_test
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"math/rand"
     7  
     8  	"github.com/Jeffail/benthos/v3/public/bloblang"
     9  )
    10  
    11  // This example demonstrates how to create Bloblang methods and functions and
    12  // execute them with a Bloblang mapping using the new V2 methods, which adds
    13  // support to our functions and methods for optional named parameters.
    14  func Example_bloblangFunctionPluginV2() {
    15  	multiplyWrongSpec := bloblang.NewPluginSpec().
    16  		Description("Multiplies two numbers together but gets it slightly wrong. Whoops.").
    17  		Param(bloblang.NewFloat64Param("left").Description("The first of two numbers to multiply.")).
    18  		Param(bloblang.NewFloat64Param("right").Description("The second of two numbers to multiply."))
    19  
    20  	if err := bloblang.RegisterFunctionV2(
    21  		"multiply_but_always_slightly_wrong", multiplyWrongSpec,
    22  		func(args *bloblang.ParsedParams) (bloblang.Function, error) {
    23  			left, err := args.GetFloat64("left")
    24  			if err != nil {
    25  				return nil, err
    26  			}
    27  
    28  			right, err := args.GetFloat64("right")
    29  			if err != nil {
    30  				return nil, err
    31  			}
    32  
    33  			return func() (interface{}, error) {
    34  				return left*right + 0.02, nil
    35  			}, nil
    36  		}); err != nil {
    37  		panic(err)
    38  	}
    39  
    40  	// Our function now optionally supports named parameters, when a function is
    41  	// instantiated with unamed parameters they must follow the order in which
    42  	// the parameters are registered.
    43  	mapping := `
    44  root.num_ab = multiply_but_always_slightly_wrong(left: this.a, right: this.b)
    45  root.num_cd = multiply_but_always_slightly_wrong(this.c, this.d)
    46  `
    47  
    48  	exe, err := bloblang.Parse(mapping)
    49  	if err != nil {
    50  		panic(err)
    51  	}
    52  
    53  	res, err := exe.Query(map[string]interface{}{
    54  		"a": 1.2, "b": 2.6, "c": 5.3, "d": 8.2,
    55  	})
    56  	if err != nil {
    57  		panic(err)
    58  	}
    59  
    60  	jsonBytes, err := json.Marshal(res)
    61  	if err != nil {
    62  		panic(err)
    63  	}
    64  
    65  	fmt.Println(string(jsonBytes))
    66  	// Output: {"num_ab":3.14,"num_cd":43.48}
    67  }
    68  
    69  // This example demonstrates how to create Bloblang methods and functions and
    70  // execute them with a Bloblang mapping using the new V2 methods, which adds
    71  // support to our functions and methods for optional named parameters.
    72  func Example_bloblangMethodPluginV2() {
    73  	hugStringSpec := bloblang.NewPluginSpec().
    74  		Description("Wraps a string with a prefix and suffix.").
    75  		Param(bloblang.NewStringParam("prefix").Description("The prefix to insert.")).
    76  		Param(bloblang.NewStringParam("suffix").Description("The suffix to append."))
    77  
    78  	if err := bloblang.RegisterMethodV2("hug_string", hugStringSpec, func(args *bloblang.ParsedParams) (bloblang.Method, error) {
    79  		prefix, err := args.GetString("prefix")
    80  		if err != nil {
    81  			return nil, err
    82  		}
    83  
    84  		suffix, err := args.GetString("suffix")
    85  		if err != nil {
    86  			return nil, err
    87  		}
    88  
    89  		return bloblang.StringMethod(func(s string) (interface{}, error) {
    90  			return prefix + s + suffix, nil
    91  		}), nil
    92  	}); err != nil {
    93  		panic(err)
    94  	}
    95  
    96  	reverseSpec := bloblang.NewPluginSpec().
    97  		Description("Reverses the order of an array target, but sometimes it randomly doesn't. Whoops.")
    98  
    99  	if err := bloblang.RegisterMethodV2("sometimes_reverse", reverseSpec, func(*bloblang.ParsedParams) (bloblang.Method, error) {
   100  		rand := rand.New(rand.NewSource(0))
   101  		return bloblang.ArrayMethod(func(in []interface{}) (interface{}, error) {
   102  			if rand.Int()%3 == 0 {
   103  				// Whoopsie
   104  				return in, nil
   105  			}
   106  			out := make([]interface{}, len(in))
   107  			copy(out, in)
   108  			for i, j := 0, len(out)-1; i < j; i, j = i+1, j-1 {
   109  				out[i], out[j] = out[j], out[i]
   110  			}
   111  			return out, nil
   112  		}), nil
   113  	}); err != nil {
   114  		panic(err)
   115  	}
   116  
   117  	// Our methods now optionally support named parameters, when a method is
   118  	// instantiated with unamed parameters they must follow the order in which
   119  	// the parameters are registered.
   120  	mapping := `
   121  root.new_summary = this.summary.hug_string(prefix: "meow", suffix: "woof")
   122  root.reversed = this.names.sometimes_reverse()
   123  `
   124  
   125  	exe, err := bloblang.Parse(mapping)
   126  	if err != nil {
   127  		panic(err)
   128  	}
   129  
   130  	res, err := exe.Query(map[string]interface{}{
   131  		"summary": "quack",
   132  		"names":   []interface{}{"denny", "pixie", "olaf", "jen", "spuz"},
   133  	})
   134  	if err != nil {
   135  		panic(err)
   136  	}
   137  
   138  	jsonBytes, err := json.Marshal(res)
   139  	if err != nil {
   140  		panic(err)
   141  	}
   142  
   143  	fmt.Println(string(jsonBytes))
   144  	// Output: {"new_summary":"meowquackwoof","reversed":["spuz","jen","olaf","pixie","denny"]}
   145  }