github.com/mweagle/Sparta@v1.15.0/archetype/xformer/xformer.go (about)

     1  package xformer
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"regexp"
     7  
     8  	awsEvents "github.com/aws/aws-lambda-go/events"
     9  	jmesPath "github.com/jmespath/go-jmespath"
    10  )
    11  
    12  type xformRegexpResults struct {
    13  	re            *regexp.Regexp
    14  	reErr         error
    15  	capturedNames map[string]string
    16  }
    17  
    18  // XFormableData is the struct that supports transforming the record
    19  type XFormableData struct {
    20  	rawData    []byte
    21  	stringData string
    22  	jsonData   map[string]interface{}
    23  	xformErr   error
    24  	regexps    map[string]*xformRegexpResults
    25  }
    26  
    27  func (xf *XFormableData) regexpGroupValue(regexpString string, groupName string) interface{} {
    28  	results, resultsExist := xf.regexps[regexpString]
    29  	if !resultsExist {
    30  		if xf.stringData == "" {
    31  			xf.stringData = string(xf.rawData)
    32  		}
    33  		// Run it...
    34  		re, reErr := regexp.Compile(regexpString)
    35  		xformResults := &xformRegexpResults{
    36  			re:    re,
    37  			reErr: reErr,
    38  		}
    39  		// Parse it...
    40  		if reErr == nil {
    41  			xformResults.capturedNames = make(map[string]string)
    42  			matches := xformResults.re.FindStringSubmatch(xf.stringData)
    43  			if len(matches) > 0 {
    44  				for i, eachName := range xformResults.re.SubexpNames() {
    45  					// Ignore the whole regexp match and unnamed groups
    46  					if i == 0 || eachName == "" {
    47  						continue
    48  					}
    49  					xformResults.capturedNames[eachName] = matches[i]
    50  				}
    51  			}
    52  		}
    53  		xf.regexps[regexpString] = xformResults
    54  		results = xformResults
    55  	}
    56  	if results == nil || results.reErr != nil {
    57  		return nil
    58  	}
    59  	return results.capturedNames[groupName]
    60  }
    61  
    62  // RegExpGroup captures the output as a String
    63  func (xf *XFormableData) RegExpGroup(regexpString string, groupName string) interface{} {
    64  	value := xf.regexpGroupValue(regexpString, groupName)
    65  	if value == nil {
    66  		return ""
    67  	}
    68  	return xf.RegExpGroupAsFormattedString(regexpString, groupName, "%s")
    69  }
    70  
    71  // RegExpGroupAsFormattedString captures the output as a String
    72  func (xf *XFormableData) RegExpGroupAsFormattedString(regexpString string,
    73  	groupName string,
    74  	formatSpecifier string) interface{} {
    75  	value := xf.regexpGroupValue(regexpString, groupName)
    76  	if value == nil {
    77  		return ""
    78  	}
    79  	return fmt.Sprintf(formatSpecifier, value)
    80  }
    81  
    82  // RegExpGroupAsJSON captures the output as a JSON blob
    83  func (xf *XFormableData) RegExpGroupAsJSON(regexpString string, groupName string) interface{} {
    84  	value := xf.regexpGroupValue(regexpString, groupName)
    85  	if value == nil {
    86  		return nil
    87  	}
    88  	marshalResult, marshalResultErr := json.Marshal(value)
    89  	if marshalResultErr != nil {
    90  		xf.xformErr = marshalResultErr
    91  		return nil
    92  	}
    93  	return string(marshalResult)
    94  }
    95  
    96  func (xf *XFormableData) jmesValue(pathSpec string) interface{} {
    97  	if xf.jsonData == nil {
    98  		xf.jsonData = make(map[string]interface{})
    99  		unmarshalErr := json.Unmarshal(xf.rawData, &xf.jsonData)
   100  		if unmarshalErr != nil {
   101  			xf.xformErr = unmarshalErr
   102  			return nil
   103  		}
   104  	}
   105  
   106  	precompiled, compileErr := jmesPath.Compile(pathSpec)
   107  	if compileErr != nil {
   108  		xf.xformErr = compileErr
   109  		return nil
   110  	}
   111  	result, resultErr := precompiled.Search(xf.jsonData)
   112  	if resultErr != nil {
   113  		xf.xformErr = compileErr
   114  		return nil
   115  	}
   116  	return result
   117  }
   118  
   119  // JMESPath runs the query
   120  func (xf *XFormableData) JMESPath(pathSpec string) interface{} {
   121  	value := xf.jmesValue(pathSpec)
   122  	if value == nil {
   123  		return nil
   124  	}
   125  	marshalResult, marshalResultErr := json.Marshal(value)
   126  	if marshalResultErr != nil {
   127  		xf.xformErr = marshalResultErr
   128  		return nil
   129  	}
   130  	return string(marshalResult)
   131  }
   132  
   133  // JMESPathAsString returns the value at pathSpec using a string formatter
   134  func (xf *XFormableData) JMESPathAsString(pathSpec string) interface{} {
   135  	return xf.JMESPathAsFormattedString(pathSpec, "%s")
   136  }
   137  
   138  // JMESPathAsFormattedString returns the value at pathSpec using the provided go
   139  // format specifier
   140  func (xf *XFormableData) JMESPathAsFormattedString(pathSpec string, formatSpecifier string) interface{} {
   141  	value := xf.jmesValue(pathSpec)
   142  	if value == nil {
   143  		return nil
   144  	}
   145  	return fmt.Sprintf(formatSpecifier, value)
   146  }
   147  
   148  // KinesisEventHeaderInfo is the common header info in the KinesisFirehoseInput event
   149  type KinesisEventHeaderInfo struct {
   150  	InvocationID           string
   151  	DeliveryStreamArn      string
   152  	SourceKinesisStreamArn string
   153  	Region                 string
   154  }
   155  
   156  // XFormer is the transformer
   157  type XFormer struct {
   158  	Data                        *XFormableData
   159  	KinesisEventHeader          *KinesisEventHeaderInfo
   160  	RecordID                    string
   161  	Metadata                    *awsEvents.KinesisFirehoseRecordMetadata
   162  	ApproximateArrivalTimestamp awsEvents.MilliSecondsEpochTime
   163  }
   164  
   165  // Error returns the potentially nil error from applying the
   166  // transform
   167  func (xf *XFormer) Error() error {
   168  	return xf.Data.xformErr
   169  }
   170  
   171  // NewKinesisFirehoseEventXFormer returns a new XFormer pointer initialized with the
   172  // awsEvents.KinesisFirehoseEventRecord data
   173  func NewKinesisFirehoseEventXFormer(kinesisEventHeader *KinesisEventHeaderInfo,
   174  	record *awsEvents.KinesisFirehoseEventRecord) (*XFormer, error) {
   175  	return &XFormer{
   176  		Data: &XFormableData{
   177  			rawData: record.Data,
   178  			regexps: make(map[string]*xformRegexpResults),
   179  		},
   180  		KinesisEventHeader:          kinesisEventHeader,
   181  		RecordID:                    record.RecordID,
   182  		Metadata:                    &record.KinesisFirehoseRecordMetadata,
   183  		ApproximateArrivalTimestamp: record.ApproximateArrivalTimestamp,
   184  	}, nil
   185  }