text: package expression
  
  import (
  	"fmt"
  	"strings"
  
  	"github.com/aws/aws-sdk-go/service/dynamodb"
  	"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
  )
  
  // ValueBuilder represents an item attribute value operand and implements the
  // OperandBuilder interface. Methods and functions in the package take
  // ValueBuilder as an argument and establishes relationships between operands.
  // ValueBuilder should only be initialized using the function Value().
  //
  // Example:
  //
  //     // Create a ValueBuilder representing the string "aValue"
  //     valueBuilder := expression.Value("aValue")
  type ValueBuilder struct {
  	value interface{}
  }
  
  // NameBuilder represents a name of a top level item attribute or a nested
  // attribute. Since NameBuilder represents a DynamoDB Operand, it implements the
  // OperandBuilder interface. Methods and functions in the package take
  // NameBuilder as an argument and establishes relationships between operands.
  // NameBuilder should only be initialized using the function Name().
  //
  // Example:
  //
  //     // Create a NameBuilder representing the item attribute "aName"
  //     nameBuilder := expression.Name("aName")
  type NameBuilder struct {
  	name string
  }
  
  // SizeBuilder represents the output of the function size ("someName"), which
  // evaluates to the size of the item attribute defined by "someName". Since
  // SizeBuilder represents an operand, SizeBuilder implements the OperandBuilder
  // interface. Methods and functions in the package take SizeBuilder as an
  // argument and establishes relationships between operands. SizeBuilder should
  // only be initialized using the function Size().
  //
  // Example:
  //
  //     // Create a SizeBuilder representing the size of the item attribute
  //     // "aName"
  //     sizeBuilder := expression.Name("aName").Size()
  type SizeBuilder struct {
  	nameBuilder NameBuilder
  }
  
  // KeyBuilder represents either the partition key or the sort key, both of which
  // are top level attributes to some item in DynamoDB. Since KeyBuilder
  // represents an operand, KeyBuilder implements the OperandBuilder interface.
  // Methods and functions in the package take KeyBuilder as an argument and
  // establishes relationships between operands. However, KeyBuilder should only
  // be used to describe Key Condition Expressions. KeyBuilder should only be
  // initialized using the function Key().
  //
  // Example:
  //
  //     // Create a KeyBuilder representing the item key "aKey"
  //     keyBuilder := expression.Key("aKey")
  type KeyBuilder struct {
  	key string
  }
  
  // setValueMode specifies the type of SetValueBuilder. The default value is
  // unsetValue so that an UnsetParameterError when BuildOperand() is called on an
  // empty SetValueBuilder.
  type setValueMode int
  
  const (
  	unsetValue setValueMode = iota
  	plusValueMode
  	minusValueMode
  	listAppendValueMode
  	ifNotExistsValueMode
  )
  
  // SetValueBuilder represents the outcome of operator functions supported by the
  // DynamoDB Set operation. The operator functions are the following:
  //     Plus()  // Represents the "+" operator
  //     Minus() // Represents the "-" operator
  //     ListAppend()
  //     IfNotExists()
  // For documentation on the above functions,
  // see: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET
  // Since SetValueBuilder represents an operand, it implements the OperandBuilder
  // interface. SetValueBuilder structs are used as arguments to the Set()
  // function. SetValueBuilders should only initialize a SetValueBuilder using the
  // functions listed above.
  type SetValueBuilder struct {
  	leftOperand  OperandBuilder
  	rightOperand OperandBuilder
  	mode         setValueMode
  }
  
  // Operand represents an item attribute name or value in DynamoDB. The
  // relationship between Operands specified by various builders such as
  // ConditionBuilders and UpdateBuilders for example is processed internally to
  // write Condition Expressions and Update Expressions respectively.
  type Operand struct {
  	exprNode exprNode
  }
  
  // OperandBuilder represents the idea of Operand which are building blocks to
  // DynamoDB Expressions. Package methods and functions can establish
  // relationships between operands, representing DynamoDB Expressions. The method
  // BuildOperand() is called recursively when the Build() method on the type
  // Builder is called. BuildOperand() should never be called externally.
  // OperandBuilder and BuildOperand() are exported to allow package functions to
  // take an interface as an argument.
  type OperandBuilder interface {
  	BuildOperand() (Operand, error)
  }
  
  // Name creates a NameBuilder. The argument should represent the desired item
  // attribute. It is possible to reference nested item attributes by using
  // square brackets for lists and dots for maps. For documentation on specifying
  // item attributes,
  // see: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.Attributes.html
  //
  // Example:
  //
  //     // Specify a top-level attribute
  //     name := expression.Name("TopLevel")
  //     // Specify a nested attribute
  //     nested := expression.Name("Record[6].SongList")
  //     // Use Name() to create a condition expression
  //     condition := expression.Name("foo").Equal(expression.Name("bar"))
  func Name(name string) NameBuilder {
  	return NameBuilder{
  		name: name,
  	}
  }
  
  // Value creates a ValueBuilder. The argument should represent the desired item
  // attribute. The value is marshalled using the dynamodbattribute package by the
  // Build() method for type Builder.
  //
  // Example:
  //
  //     // Use Value() to create a condition expression
  //     condition := expression.Name("foo").Equal(expression.Value(10))
  func Value(value interface{}) ValueBuilder {
  	return ValueBuilder{
  		value: value,
  	}
  }
  
  // Size creates a SizeBuilder representing the size of the item attribute
  // specified by the argument NameBuilder. Size() is only valid for certain types
  // of item attributes. For documentation,
  // see: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html
  // SizeBuilder is only a valid operand in Condition Expressions and Filter
  // Expressions.
  //
  // Example:
  //
  //     // Use Size() to create a condition expression
  //     condition := expression.Name("foo").Size().Equal(expression.Value(10))
  //
  // Expression Equivalent:
  //
  //     expression.Name("aName").Size()
  //     "size (aName)"
  func (nb NameBuilder) Size() SizeBuilder {
  	return SizeBuilder{
  		nameBuilder: nb,
  	}
  }
  
  // Size creates a SizeBuilder representing the size of the item attribute
  // specified by the argument NameBuilder. Size() is only valid for certain types
  // of item attributes. For documentation,
  // see: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html
  // SizeBuilder is only a valid operand in Condition Expressions and Filter
  // Expressions.
  //
  // Example:
  //
  //     // Use Size() to create a condition expression
  //     condition := expression.Size(expression.Name("foo")).Equal(expression.Value(10))
  //
  // Expression Equivalent:
  //
  //     expression.Size(expression.Name("aName"))
  //     "size (aName)"
  func Size(nameBuilder NameBuilder) SizeBuilder {
  	return nameBuilder.Size()
  }
  
  // Key creates a KeyBuilder. The argument should represent the desired partition
  // key or sort key value. KeyBuilders should only be used to specify
  // relationships for Key Condition Expressions. When referring to the partition
  // key or sort key in any other Expression, use Name().
  //
  // Example:
  //
  //     // Use Key() to create a key condition expression
  //     keyCondition := expression.Key("foo").Equal(expression.Value("bar"))
  func Key(key string) KeyBuilder {
  	return KeyBuilder{
  		key: key,
  	}
  }
  
  // Plus creates a SetValueBuilder to be used in as an argument to Set(). The
  // arguments can either be NameBuilders or ValueBuilders. Plus() only supports
  // DynamoDB Number types, so the ValueBuilder must be a Number and the
  // NameBuilder must specify an item attribute of type Number.
  // More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.IncrementAndDecrement
  //
  // Example:
  //
  //     // Use Plus() to set the value of the item attribute "someName" to 5 + 10
  //     update, err := expression.Set(expression.Name("someName"), expression.Plus(expression.Value(5), expression.Value(10)))
  //
  // Expression Equivalent:
  //
  //     expression.Plus(expression.Value(5), expression.Value(10))
  //     // let :five and :ten be ExpressionAttributeValues for the values 5 and
  //     // 10 respectively.
  //     ":five + :ten"
  func Plus(leftOperand, rightOperand OperandBuilder) SetValueBuilder {
  	return SetValueBuilder{
  		leftOperand:  leftOperand,
  		rightOperand: rightOperand,
  		mode:         plusValueMode,
  	}
  }
  
  // Plus creates a SetValueBuilder to be used in as an argument to Set(). The
  // arguments can either be NameBuilders or ValueBuilders. Plus() only supports
  // DynamoDB Number types, so the ValueBuilder must be a Number and the
  // NameBuilder must specify an item attribute of type Number.
  // More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.IncrementAndDecrement
  //
  // Example:
  //
  //     // Use Plus() to set the value of the item attribute "someName" to the
  //     // numeric value of item attribute "aName" incremented by 10
  //     update, err := expression.Set(expression.Name("someName"), expression.Name("aName").Plus(expression.Value(10)))
  //
  // Expression Equivalent:
  //
  //     expression.Name("aName").Plus(expression.Value(10))
  //     // let :ten be ExpressionAttributeValues representing the value 10
  //     "aName + :ten"
  func (nb NameBuilder) Plus(rightOperand OperandBuilder) SetValueBuilder {
  	return Plus(nb, rightOperand)
  }
  
  // Plus creates a SetValueBuilder to be used in as an argument to Set(). The
  // arguments can either be NameBuilders or ValueBuilders. Plus() only supports
  // DynamoDB Number types, so the ValueBuilder must be a Number and the
  // NameBuilder must specify an item attribute of type Number.
  // More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.IncrementAndDecrement
  //
  // Example:
  //
  //     // Use Plus() to set the value of the item attribute "someName" to 5 + 10
  //     update, err := expression.Set(expression.Name("someName"), expression.Value(5).Plus(expression.Value(10)))
  //
  // Expression Equivalent:
  //
  //     expression.Value(5).Plus(expression.Value(10))
  //     // let :five and :ten be ExpressionAttributeValues representing the value
  //     // 5 and 10 respectively
  //     ":five + :ten"
  func (vb ValueBuilder) Plus(rightOperand OperandBuilder) SetValueBuilder {
  	return Plus(vb, rightOperand)
  }
  
  // Minus creates a SetValueBuilder to be used in as an argument to Set(). The
  // arguments can either be NameBuilders or ValueBuilders. Minus() only supports
  // DynamoDB Number types, so the ValueBuilder must be a Number and the
  // NameBuilder must specify an item attribute of type Number.
  // More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.IncrementAndDecrement
  //
  // Example:
  //
  //     // Use Minus() to set the value of item attribute "someName" to 5 - 10
  //     update, err := expression.Set(expression.Name("someName"), expression.Minus(expression.Value(5), expression.Value(10)))
  //
  // Expression Equivalent:
  //
  //     expression.Minus(expression.Value(5), expression.Value(10))
  //     // let :five and :ten be ExpressionAttributeValues for the values 5 and
  //     // 10 respectively.
  //     ":five - :ten"
  func Minus(leftOperand, rightOperand OperandBuilder) SetValueBuilder {
  	return SetValueBuilder{
  		leftOperand:  leftOperand,
  		rightOperand: rightOperand,
  		mode:         minusValueMode,
  	}
  }
  
  // Minus creates a SetValueBuilder to be used in as an argument to Set(). The
  // arguments can either be NameBuilders or ValueBuilders. Minus() only supports
  // DynamoDB Number types, so the ValueBuilder must be a Number and the
  // NameBuilder must specify an item attribute of type Number.
  // More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.IncrementAndDecrement
  //
  // Example:
  //
  //     // Use Minus() to set the value of item attribute "someName" to the
  //     // numeric value of "aName" decremented by 10
  //     update, err := expression.Set(expression.Name("someName"), expression.Name("aName").Minus(expression.Value(10)))
  //
  // Expression Equivalent:
  //
  //     expression.Name("aName").Minus(expression.Value(10)))
  //     // let :ten be ExpressionAttributeValues represent the value 10
  //     "aName - :ten"
  func (nb NameBuilder) Minus(rightOperand OperandBuilder) SetValueBuilder {
  	return Minus(nb, rightOperand)
  }
  
  // Minus creates a SetValueBuilder to be used in as an argument to Set(). The
  // arguments can either be NameBuilders or ValueBuilders. Minus() only supports
  // DynamoDB Number types, so the ValueBuilder must be a Number and the
  // NameBuilder must specify an item attribute of type Number.
  // More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.IncrementAndDecrement
  //
  // Example:
  //
  //     // Use Minus() to set the value of item attribute "someName" to 5 - 10
  //     update, err := expression.Set(expression.Name("someName"), expression.Value(5).Minus(expression.Value(10)))
  //
  // Expression Equivalent:
  //
  //     expression.Value(5).Minus(expression.Value(10))
  //     // let :five and :ten be ExpressionAttributeValues for the values 5 and
  //     // 10 respectively.
  //     ":five - :ten"
  func (vb ValueBuilder) Minus(rightOperand OperandBuilder) SetValueBuilder {
  	return Minus(vb, rightOperand)
  }
  
  // ListAppend creates a SetValueBuilder to be used in as an argument to Set().
  // The arguments can either be NameBuilders or ValueBuilders. ListAppend() only
  // supports DynamoDB List types, so the ValueBuilder must be a List and the
  // NameBuilder must specify an item attribute of type List.
  // More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.UpdatingListElements
  //
  // Example:
  //
  //     // Use ListAppend() to set item attribute "someName" to the item
  //     // attribute "nameOfList" with "some" and "list" appended to it
  //     update, err := expression.Set(expression.Name("someName"), expression.ListAppend(expression.Name("nameOfList"), expression.Value([]string{"some", "list"})))
  //
  // Expression Equivalent:
  //
  //     expression.ListAppend(expression.Name("nameOfList"), expression.Value([]string{"some", "list"})
  //     // let :list be a ExpressionAttributeValue representing the list
  //     // containing "some" and "list".
  //     "list_append (nameOfList, :list)"
  func ListAppend(leftOperand, rightOperand OperandBuilder) SetValueBuilder {
  	return SetValueBuilder{
  		leftOperand:  leftOperand,
  		rightOperand: rightOperand,
  		mode:         listAppendValueMode,
  	}
  }
  
  // ListAppend creates a SetValueBuilder to be used in as an argument to Set().
  // The arguments can either be NameBuilders or ValueBuilders. ListAppend() only
  // supports DynamoDB List types, so the ValueBuilder must be a List and the
  // NameBuilder must specify an item attribute of type List.
  // More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.UpdatingListElements
  //
  // Example:
  //
  //     // Use ListAppend() to set item attribute "someName" to the item
  //     // attribute "nameOfList" with "some" and "list" appended to it
  //     update, err := expression.Set(expression.Name("someName"), expression.Name("nameOfList").ListAppend(expression.Value([]string{"some", "list"})))
  //
  // Expression Equivalent:
  //
  //     expression.Name("nameOfList").ListAppend(expression.Value([]string{"some", "list"})
  //     // let :list be a ExpressionAttributeValue representing the list
  //     // containing "some" and "list".
  //     "list_append (nameOfList, :list)"
  func (nb NameBuilder) ListAppend(rightOperand OperandBuilder) SetValueBuilder {
  	return ListAppend(nb, rightOperand)
  }
  
  // ListAppend creates a SetValueBuilder to be used in as an argument to Set().
  // The arguments can either be NameBuilders or ValueBuilders. ListAppend() only
  // supports DynamoDB List types, so the ValueBuilder must be a List and the
  // NameBuilder must specify an item attribute of type List.
  // More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.UpdatingListElements
  //
  // Example:
  //
  //     // Use ListAppend() to set item attribute "someName" to a string list
  //     // equal to {"a", "list", "some", "list"}
  //     update, err := expression.Set(expression.Name("someName"), expression.Value([]string{"a", "list"}).ListAppend(expression.Value([]string{"some", "list"})))
  //
  // Expression Equivalent:
  //
  //     expression.Name([]string{"a", "list"}).ListAppend(expression.Value([]string{"some", "list"})
  //     // let :list1 and :list2 be a ExpressionAttributeValue representing the
  //     // list {"a", "list"} and {"some", "list"} respectively
  //     "list_append (:list1, :list2)"
  func (vb ValueBuilder) ListAppend(rightOperand OperandBuilder) SetValueBuilder {
  	return ListAppend(vb, rightOperand)
  }
  
  // IfNotExists creates a SetValueBuilder to be used in as an argument to Set().
  // The first argument must be a NameBuilder representing the name where the new
  // item attribute is created. The second argument can either be a NameBuilder or
  // a ValueBuilder. In the case that it is a NameBuilder, the value of the item
  // attribute at the name specified becomes the value of the new item attribute.
  // More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.PreventingAttributeOverwrites
  //
  // Example:
  //
  //     // Use IfNotExists() to set item attribute "someName" to value 5 if
  //     // "someName" does not exist yet. (Prevents overwrite)
  //     update, err := expression.Set(expression.Name("someName"), expression.IfNotExists(expression.Name("someName"), expression.Value(5)))
  //
  // Expression Equivalent:
  //
  //     expression.IfNotExists(expression.Name("someName"), expression.Value(5))
  //     // let :five be a ExpressionAttributeValue representing the value 5
  //     "if_not_exists (someName, :five)"
  func IfNotExists(name NameBuilder, setValue OperandBuilder) SetValueBuilder {
  	return SetValueBuilder{
  		leftOperand:  name,
  		rightOperand: setValue,
  		mode:         ifNotExistsValueMode,
  	}
  }
  
  // IfNotExists creates a SetValueBuilder to be used in as an argument to Set().
  // The first argument must be a NameBuilder representing the name where the new
  // item attribute is created. The second argument can either be a NameBuilder or
  // a ValueBuilder. In the case that it is a NameBuilder, the value of the item
  // attribute at the name specified becomes the value of the new item attribute.
  // More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.PreventingAttributeOverwrites
  //
  // Example:
  //
  //     // Use IfNotExists() to set item attribute "someName" to value 5 if
  //     // "someName" does not exist yet. (Prevents overwrite)
  //     update, err := expression.Set(expression.Name("someName"), expression.Name("someName").IfNotExists(expression.Value(5)))
  //
  // Expression Equivalent:
  //
  //     expression.Name("someName").IfNotExists(expression.Value(5))
  //     // let :five be a ExpressionAttributeValue representing the value 5
  //     "if_not_exists (someName, :five)"
  func (nb NameBuilder) IfNotExists(rightOperand OperandBuilder) SetValueBuilder {
  	return IfNotExists(nb, rightOperand)
  }
  
  // BuildOperand creates an Operand struct which are building blocks to DynamoDB
  // Expressions. Package methods and functions can establish relationships
  // between operands, representing DynamoDB Expressions. The method
  // BuildOperand() is called recursively when the Build() method on the type
  // Builder is called. BuildOperand() should never be called externally.
  // BuildOperand() aliases all strings to avoid stepping over DynamoDB's reserved
  // words.
  // More information on reserved words at http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html
  func (nb NameBuilder) BuildOperand() (Operand, error) {
  	if nb.name == "" {
  		return Operand{}, newUnsetParameterError("BuildOperand", "NameBuilder")
  	}
  
  	node := exprNode{
  		names: []string{},
  	}
  
  	nameSplit := strings.Split(nb.name, ".")
  	fmtNames := make([]string, 0, len(nameSplit))
  
  	for _, word := range nameSplit {
  		var substr string
  		if word == "" {
  			return Operand{}, newInvalidParameterError("BuildOperand", "NameBuilder")
  		}
  
  		if word[len(word)-1] == ']' {
  			for j, char := range word {
  				if char == '[' {
  					substr = word[j:]
  					word = word[:j]
  					break
  				}
  			}
  		}
  
  		if word == "" {
  			return Operand{}, newInvalidParameterError("BuildOperand", "NameBuilder")
  		}
  
  		// Create a string with special characters that can be substituted later: $p
  		node.names = append(node.names, word)
  		fmtNames = append(fmtNames, "$n"+substr)
  	}
  	node.fmtExpr = strings.Join(fmtNames, ".")
  	return Operand{
  		exprNode: node,
  	}, nil
  }
  
  // BuildOperand creates an Operand struct which are building blocks to DynamoDB
  // Expressions. Package methods and functions can establish relationships
  // between operands, representing DynamoDB Expressions. The method
  // BuildOperand() is called recursively when the Build() method on the type
  // Builder is called. BuildOperand() should never be called externally.
  // BuildOperand() aliases all strings to avoid stepping over DynamoDB's reserved
  // words.
  // More information on reserved words at http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html
  func (vb ValueBuilder) BuildOperand() (Operand, error) {
  	expr, err := dynamodbattribute.Marshal(vb.value)
  	if err != nil {
  		return Operand{}, newInvalidParameterError("BuildOperand", "ValueBuilder")
  	}
  
  	// Create a string with special characters that can be substituted later: $v
  	operand := Operand{
  		exprNode: exprNode{
  			values:  []dynamodb.AttributeValue{*expr},
  			fmtExpr: "$v",
  		},
  	}
  	return operand, nil
  }
  
  // BuildOperand creates an Operand struct which are building blocks to DynamoDB
  // Expressions. Package methods and functions can establish relationships
  // between operands, representing DynamoDB Expressions. The method
  // BuildOperand() is called recursively when the Build() method on the type
  // Builder is called. BuildOperand() should never be called externally.
  // BuildOperand() aliases all strings to avoid stepping over DynamoDB's reserved
  // words.
  // More information on reserved words at http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html
  func (sb SizeBuilder) BuildOperand() (Operand, error) {
  	operand, err := sb.nameBuilder.BuildOperand()
  	operand.exprNode.fmtExpr = "size (" + operand.exprNode.fmtExpr + ")"
  
  	return operand, err
  }
  
  // BuildOperand creates an Operand struct which are building blocks to DynamoDB
  // Expressions. Package methods and functions can establish relationships
  // between operands, representing DynamoDB Expressions. The method
  // BuildOperand() is called recursively when the Build() method on the type
  // Builder is called. BuildOperand() should never be called externally.
  // BuildOperand() aliases all strings to avoid stepping over DynamoDB's reserved
  // words.
  // More information on reserved words at http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html
  func (kb KeyBuilder) BuildOperand() (Operand, error) {
  	if kb.key == "" {
  		return Operand{}, newUnsetParameterError("BuildOperand", "KeyBuilder")
  	}
  
  	ret := Operand{
  		exprNode: exprNode{
  			names:   []string{kb.key},
  			fmtExpr: "$n",
  		},
  	}
  
  	return ret, nil
  }
  
  // BuildOperand creates an Operand struct which are building blocks to DynamoDB
  // Expressions. Package methods and functions can establish relationships
  // between operands, representing DynamoDB Expressions. The method
  // BuildOperand() is called recursively when the Build() method on the type
  // Builder is called. BuildOperand() should never be called externally.
  // BuildOperand() aliases all strings to avoid stepping over DynamoDB's reserved
  // words.
  // More information on reserved words at http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html
  func (svb SetValueBuilder) BuildOperand() (Operand, error) {
  	if svb.mode == unsetValue {
  		return Operand{}, newUnsetParameterError("BuildOperand", "SetValueBuilder")
  	}
  
  	left, err := svb.leftOperand.BuildOperand()
  	if err != nil {
  		return Operand{}, err
  	}
  	leftNode := left.exprNode
  
  	right, err := svb.rightOperand.BuildOperand()
  	if err != nil {
  		return Operand{}, err
  	}
  	rightNode := right.exprNode
  
  	node := exprNode{
  		children: []exprNode{leftNode, rightNode},
  	}
  
  	switch svb.mode {
  	case plusValueMode:
  		node.fmtExpr = "$c + $c"
  	case minusValueMode:
  		node.fmtExpr = "$c - $c"
  	case listAppendValueMode:
  		node.fmtExpr = "list_append($c, $c)"
  	case ifNotExistsValueMode:
  		node.fmtExpr = "if_not_exists($c, $c)"
  	default:
  		return Operand{}, fmt.Errorf("build operand error: unsupported mode: %v", svb.mode)
  	}
  
  	return Operand{
  		exprNode: node,
  	}, nil
  }
  