github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/legacy/helper/schema/field_reader_multi.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package schema
     5  
     6  import (
     7  	"fmt"
     8  )
     9  
    10  // MultiLevelFieldReader reads from other field readers,
    11  // merging their results along the way in a specific order. You can specify
    12  // "levels" and name them in order to read only an exact level or up to
    13  // a specific level.
    14  //
    15  // This is useful for saying things such as "read the field from the state
    16  // and config and merge them" or "read the latest value of the field".
    17  type MultiLevelFieldReader struct {
    18  	Readers map[string]FieldReader
    19  	Levels  []string
    20  }
    21  
    22  func (r *MultiLevelFieldReader) ReadField(address []string) (FieldReadResult, error) {
    23  	return r.ReadFieldMerge(address, r.Levels[len(r.Levels)-1])
    24  }
    25  
    26  func (r *MultiLevelFieldReader) ReadFieldExact(
    27  	address []string, level string) (FieldReadResult, error) {
    28  	reader, ok := r.Readers[level]
    29  	if !ok {
    30  		return FieldReadResult{}, fmt.Errorf(
    31  			"Unknown reader level: %s", level)
    32  	}
    33  
    34  	result, err := reader.ReadField(address)
    35  	if err != nil {
    36  		return FieldReadResult{}, fmt.Errorf(
    37  			"Error reading level %s: %s", level, err)
    38  	}
    39  
    40  	return result, nil
    41  }
    42  
    43  func (r *MultiLevelFieldReader) ReadFieldMerge(
    44  	address []string, level string) (FieldReadResult, error) {
    45  	var result FieldReadResult
    46  	for _, l := range r.Levels {
    47  		if r, ok := r.Readers[l]; ok {
    48  			out, err := r.ReadField(address)
    49  			if err != nil {
    50  				return FieldReadResult{}, fmt.Errorf(
    51  					"Error reading level %s: %s", l, err)
    52  			}
    53  
    54  			// TODO: computed
    55  			if out.Exists {
    56  				result = out
    57  			}
    58  		}
    59  
    60  		if l == level {
    61  			break
    62  		}
    63  	}
    64  
    65  	return result, nil
    66  }