github.com/kubeshop/testkube@v1.17.23/pkg/tcl/expressionstcl/accessor.go (about)

     1  // Copyright 2024 Testkube.
     2  //
     3  // Licensed as a Testkube Pro file under the Testkube Community
     4  // License (the "License"); you may not use this file except in compliance with
     5  // the License. You may obtain a copy of the License at
     6  //
     7  //     https://github.com/kubeshop/testkube/blob/main/licenses/TCL.txt
     8  
     9  package expressionstcl
    10  
    11  import (
    12  	"fmt"
    13  	"strings"
    14  )
    15  
    16  type accessor struct {
    17  	name     string
    18  	fallback *Expression
    19  }
    20  
    21  func newAccessor(name string) Expression {
    22  	// Map values based on wildcard
    23  	segments := strings.Split(name, ".*")
    24  	if len(segments) > 1 {
    25  		return newCall("map", []callArgument{
    26  			{expr: newAccessor(strings.Join(segments[0:len(segments)-1], ".*"))},
    27  			{expr: NewStringValue("_.value" + segments[len(segments)-1])},
    28  		})
    29  	}
    30  
    31  	// Prepare fallback based on the segments
    32  	segments = strings.Split(name, ".")
    33  	var fallback *Expression
    34  	if len(segments) > 1 {
    35  		f := newPropertyAccessor(
    36  			newAccessor(strings.Join(segments[0:len(segments)-1], ".")),
    37  			segments[len(segments)-1],
    38  		)
    39  		fallback = &f
    40  	}
    41  
    42  	return &accessor{name: name, fallback: fallback}
    43  }
    44  
    45  func (s *accessor) Type() Type {
    46  	return TypeUnknown
    47  }
    48  
    49  func (s *accessor) String() string {
    50  	return s.name
    51  }
    52  
    53  func (s *accessor) SafeString() string {
    54  	return s.String()
    55  }
    56  
    57  func (s *accessor) Template() string {
    58  	return "{{" + s.String() + "}}"
    59  }
    60  
    61  func (s *accessor) SafeResolve(m ...Machine) (v Expression, changed bool, err error) {
    62  	if m == nil {
    63  		return s, false, nil
    64  	}
    65  
    66  	for i := range m {
    67  		result, ok, err := m[i].Get(s.name)
    68  		if ok && err == nil {
    69  			return result, true, nil
    70  		}
    71  		if s.fallback != nil {
    72  			var err2 error
    73  			result, ok, err2 = (*s.fallback).SafeResolve(m...)
    74  			if ok && err2 == nil {
    75  				return result, true, nil
    76  			}
    77  		}
    78  		if err != nil {
    79  			return nil, false, fmt.Errorf("error while accessing %s: %s", s.String(), err.Error())
    80  		}
    81  	}
    82  	return s, false, nil
    83  }
    84  
    85  func (s *accessor) Resolve(m ...Machine) (v Expression, err error) {
    86  	return deepResolve(s, m...)
    87  }
    88  
    89  func (s *accessor) Static() StaticValue {
    90  	return nil
    91  }
    92  
    93  func (s *accessor) Accessors() map[string]struct{} {
    94  	return map[string]struct{}{s.name: {}}
    95  }
    96  
    97  func (s *accessor) Functions() map[string]struct{} {
    98  	return nil
    99  }