github.com/aavshr/aws-sdk-go@v1.41.3/service/dynamodb/expression/operand.go (about)

     1  package expression
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/aavshr/aws-sdk-go/service/dynamodb"
     8  	"github.com/aavshr/aws-sdk-go/service/dynamodb/dynamodbattribute"
     9  )
    10  
    11  // ValueBuilder represents an item attribute value operand and implements the
    12  // OperandBuilder interface. Methods and functions in the package take
    13  // ValueBuilder as an argument and establishes relationships between operands.
    14  // ValueBuilder should only be initialized using the function Value().
    15  //
    16  // Example:
    17  //
    18  //     // Create a ValueBuilder representing the string "aValue"
    19  //     valueBuilder := expression.Value("aValue")
    20  type ValueBuilder struct {
    21  	value interface{}
    22  }
    23  
    24  // NameBuilder represents a name of a top level item attribute or a nested
    25  // attribute. Since NameBuilder represents a DynamoDB Operand, it implements the
    26  // OperandBuilder interface. Methods and functions in the package take
    27  // NameBuilder as an argument and establishes relationships between operands.
    28  // NameBuilder should only be initialized using the function Name().
    29  //
    30  // Example:
    31  //
    32  //     // Create a NameBuilder representing the item attribute "aName"
    33  //     nameBuilder := expression.Name("aName")
    34  type NameBuilder struct {
    35  	name string
    36  }
    37  
    38  // SizeBuilder represents the output of the function size ("someName"), which
    39  // evaluates to the size of the item attribute defined by "someName". Since
    40  // SizeBuilder represents an operand, SizeBuilder implements the OperandBuilder
    41  // interface. Methods and functions in the package take SizeBuilder as an
    42  // argument and establishes relationships between operands. SizeBuilder should
    43  // only be initialized using the function Size().
    44  //
    45  // Example:
    46  //
    47  //     // Create a SizeBuilder representing the size of the item attribute
    48  //     // "aName"
    49  //     sizeBuilder := expression.Name("aName").Size()
    50  type SizeBuilder struct {
    51  	nameBuilder NameBuilder
    52  }
    53  
    54  // KeyBuilder represents either the partition key or the sort key, both of which
    55  // are top level attributes to some item in DynamoDB. Since KeyBuilder
    56  // represents an operand, KeyBuilder implements the OperandBuilder interface.
    57  // Methods and functions in the package take KeyBuilder as an argument and
    58  // establishes relationships between operands. However, KeyBuilder should only
    59  // be used to describe Key Condition Expressions. KeyBuilder should only be
    60  // initialized using the function Key().
    61  //
    62  // Example:
    63  //
    64  //     // Create a KeyBuilder representing the item key "aKey"
    65  //     keyBuilder := expression.Key("aKey")
    66  type KeyBuilder struct {
    67  	key string
    68  }
    69  
    70  // setValueMode specifies the type of SetValueBuilder. The default value is
    71  // unsetValue so that an UnsetParameterError when BuildOperand() is called on an
    72  // empty SetValueBuilder.
    73  type setValueMode int
    74  
    75  const (
    76  	unsetValue setValueMode = iota
    77  	plusValueMode
    78  	minusValueMode
    79  	listAppendValueMode
    80  	ifNotExistsValueMode
    81  )
    82  
    83  // SetValueBuilder represents the outcome of operator functions supported by the
    84  // DynamoDB Set operation. The operator functions are the following:
    85  //     Plus()  // Represents the "+" operator
    86  //     Minus() // Represents the "-" operator
    87  //     ListAppend()
    88  //     IfNotExists()
    89  // For documentation on the above functions,
    90  // see: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET
    91  // Since SetValueBuilder represents an operand, it implements the OperandBuilder
    92  // interface. SetValueBuilder structs are used as arguments to the Set()
    93  // function. SetValueBuilders should only initialize a SetValueBuilder using the
    94  // functions listed above.
    95  type SetValueBuilder struct {
    96  	leftOperand  OperandBuilder
    97  	rightOperand OperandBuilder
    98  	mode         setValueMode
    99  }
   100  
   101  // Operand represents an item attribute name or value in DynamoDB. The
   102  // relationship between Operands specified by various builders such as
   103  // ConditionBuilders and UpdateBuilders for example is processed internally to
   104  // write Condition Expressions and Update Expressions respectively.
   105  type Operand struct {
   106  	exprNode exprNode
   107  }
   108  
   109  // OperandBuilder represents the idea of Operand which are building blocks to
   110  // DynamoDB Expressions. Package methods and functions can establish
   111  // relationships between operands, representing DynamoDB Expressions. The method
   112  // BuildOperand() is called recursively when the Build() method on the type
   113  // Builder is called. BuildOperand() should never be called externally.
   114  // OperandBuilder and BuildOperand() are exported to allow package functions to
   115  // take an interface as an argument.
   116  type OperandBuilder interface {
   117  	BuildOperand() (Operand, error)
   118  }
   119  
   120  // Name creates a NameBuilder. The argument should represent the desired item
   121  // attribute. It is possible to reference nested item attributes by using
   122  // square brackets for lists and dots for maps. For documentation on specifying
   123  // item attributes,
   124  // see: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.Attributes.html
   125  //
   126  // Example:
   127  //
   128  //     // Specify a top-level attribute
   129  //     name := expression.Name("TopLevel")
   130  //     // Specify a nested attribute
   131  //     nested := expression.Name("Record[6].SongList")
   132  //     // Use Name() to create a condition expression
   133  //     condition := expression.Name("foo").Equal(expression.Name("bar"))
   134  func Name(name string) NameBuilder {
   135  	return NameBuilder{
   136  		name: name,
   137  	}
   138  }
   139  
   140  // Value creates a ValueBuilder and sets its value to the argument. The value
   141  // will be marshalled using the dynamodbattribute package, unless it is of
   142  // type dynamodb.AttributeValue, where it will be used directly.
   143  //
   144  // Empty slices and maps will be converted to NULL dynamodb.AttributeValue
   145  // values. If an empty value is required, pass a dynamodb.AttributeValue, e.g.:
   146  // emptyList := (&dynamodb.AttributeValue{}).SetL([]*dynamodb.AttributeValue{})
   147  //
   148  // Example:
   149  //
   150  //     // Use Value() to create a condition expression
   151  //     condition := expression.Name("foo").Equal(expression.Value(10))
   152  //     // Use Value() to set the value of a set expression.
   153  //     update := Set(expression.Name("greets"), expression.Value((&dynamodb.AttributeValue{}).SetS("hello")))
   154  func Value(value interface{}) ValueBuilder {
   155  	return ValueBuilder{
   156  		value: value,
   157  	}
   158  }
   159  
   160  // Size creates a SizeBuilder representing the size of the item attribute
   161  // specified by the argument NameBuilder. Size() is only valid for certain types
   162  // of item attributes. For documentation,
   163  // see: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html
   164  // SizeBuilder is only a valid operand in Condition Expressions and Filter
   165  // Expressions.
   166  //
   167  // Example:
   168  //
   169  //     // Use Size() to create a condition expression
   170  //     condition := expression.Name("foo").Size().Equal(expression.Value(10))
   171  //
   172  // Expression Equivalent:
   173  //
   174  //     expression.Name("aName").Size()
   175  //     "size (aName)"
   176  func (nb NameBuilder) Size() SizeBuilder {
   177  	return SizeBuilder{
   178  		nameBuilder: nb,
   179  	}
   180  }
   181  
   182  // Size creates a SizeBuilder representing the size of the item attribute
   183  // specified by the argument NameBuilder. Size() is only valid for certain types
   184  // of item attributes. For documentation,
   185  // see: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html
   186  // SizeBuilder is only a valid operand in Condition Expressions and Filter
   187  // Expressions.
   188  //
   189  // Example:
   190  //
   191  //     // Use Size() to create a condition expression
   192  //     condition := expression.Size(expression.Name("foo")).Equal(expression.Value(10))
   193  //
   194  // Expression Equivalent:
   195  //
   196  //     expression.Size(expression.Name("aName"))
   197  //     "size (aName)"
   198  func Size(nameBuilder NameBuilder) SizeBuilder {
   199  	return nameBuilder.Size()
   200  }
   201  
   202  // Key creates a KeyBuilder. The argument should represent the desired partition
   203  // key or sort key value. KeyBuilders should only be used to specify
   204  // relationships for Key Condition Expressions. When referring to the partition
   205  // key or sort key in any other Expression, use Name().
   206  //
   207  // Example:
   208  //
   209  //     // Use Key() to create a key condition expression
   210  //     keyCondition := expression.Key("foo").Equal(expression.Value("bar"))
   211  func Key(key string) KeyBuilder {
   212  	return KeyBuilder{
   213  		key: key,
   214  	}
   215  }
   216  
   217  // Plus creates a SetValueBuilder to be used in as an argument to Set(). The
   218  // arguments can either be NameBuilders or ValueBuilders. Plus() only supports
   219  // DynamoDB Number types, so the ValueBuilder must be a Number and the
   220  // NameBuilder must specify an item attribute of type Number.
   221  // More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.IncrementAndDecrement
   222  //
   223  // Example:
   224  //
   225  //     // Use Plus() to set the value of the item attribute "someName" to 5 + 10
   226  //     update, err := expression.Set(expression.Name("someName"), expression.Plus(expression.Value(5), expression.Value(10)))
   227  //
   228  // Expression Equivalent:
   229  //
   230  //     expression.Plus(expression.Value(5), expression.Value(10))
   231  //     // let :five and :ten be ExpressionAttributeValues for the values 5 and
   232  //     // 10 respectively.
   233  //     ":five + :ten"
   234  func Plus(leftOperand, rightOperand OperandBuilder) SetValueBuilder {
   235  	return SetValueBuilder{
   236  		leftOperand:  leftOperand,
   237  		rightOperand: rightOperand,
   238  		mode:         plusValueMode,
   239  	}
   240  }
   241  
   242  // Plus creates a SetValueBuilder to be used in as an argument to Set(). The
   243  // arguments can either be NameBuilders or ValueBuilders. Plus() only supports
   244  // DynamoDB Number types, so the ValueBuilder must be a Number and the
   245  // NameBuilder must specify an item attribute of type Number.
   246  // More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.IncrementAndDecrement
   247  //
   248  // Example:
   249  //
   250  //     // Use Plus() to set the value of the item attribute "someName" to the
   251  //     // numeric value of item attribute "aName" incremented by 10
   252  //     update, err := expression.Set(expression.Name("someName"), expression.Name("aName").Plus(expression.Value(10)))
   253  //
   254  // Expression Equivalent:
   255  //
   256  //     expression.Name("aName").Plus(expression.Value(10))
   257  //     // let :ten be ExpressionAttributeValues representing the value 10
   258  //     "aName + :ten"
   259  func (nb NameBuilder) Plus(rightOperand OperandBuilder) SetValueBuilder {
   260  	return Plus(nb, rightOperand)
   261  }
   262  
   263  // Plus creates a SetValueBuilder to be used in as an argument to Set(). The
   264  // arguments can either be NameBuilders or ValueBuilders. Plus() only supports
   265  // DynamoDB Number types, so the ValueBuilder must be a Number and the
   266  // NameBuilder must specify an item attribute of type Number.
   267  // More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.IncrementAndDecrement
   268  //
   269  // Example:
   270  //
   271  //     // Use Plus() to set the value of the item attribute "someName" to 5 + 10
   272  //     update, err := expression.Set(expression.Name("someName"), expression.Value(5).Plus(expression.Value(10)))
   273  //
   274  // Expression Equivalent:
   275  //
   276  //     expression.Value(5).Plus(expression.Value(10))
   277  //     // let :five and :ten be ExpressionAttributeValues representing the value
   278  //     // 5 and 10 respectively
   279  //     ":five + :ten"
   280  func (vb ValueBuilder) Plus(rightOperand OperandBuilder) SetValueBuilder {
   281  	return Plus(vb, rightOperand)
   282  }
   283  
   284  // Minus creates a SetValueBuilder to be used in as an argument to Set(). The
   285  // arguments can either be NameBuilders or ValueBuilders. Minus() only supports
   286  // DynamoDB Number types, so the ValueBuilder must be a Number and the
   287  // NameBuilder must specify an item attribute of type Number.
   288  // More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.IncrementAndDecrement
   289  //
   290  // Example:
   291  //
   292  //     // Use Minus() to set the value of item attribute "someName" to 5 - 10
   293  //     update, err := expression.Set(expression.Name("someName"), expression.Minus(expression.Value(5), expression.Value(10)))
   294  //
   295  // Expression Equivalent:
   296  //
   297  //     expression.Minus(expression.Value(5), expression.Value(10))
   298  //     // let :five and :ten be ExpressionAttributeValues for the values 5 and
   299  //     // 10 respectively.
   300  //     ":five - :ten"
   301  func Minus(leftOperand, rightOperand OperandBuilder) SetValueBuilder {
   302  	return SetValueBuilder{
   303  		leftOperand:  leftOperand,
   304  		rightOperand: rightOperand,
   305  		mode:         minusValueMode,
   306  	}
   307  }
   308  
   309  // Minus creates a SetValueBuilder to be used in as an argument to Set(). The
   310  // arguments can either be NameBuilders or ValueBuilders. Minus() only supports
   311  // DynamoDB Number types, so the ValueBuilder must be a Number and the
   312  // NameBuilder must specify an item attribute of type Number.
   313  // More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.IncrementAndDecrement
   314  //
   315  // Example:
   316  //
   317  //     // Use Minus() to set the value of item attribute "someName" to the
   318  //     // numeric value of "aName" decremented by 10
   319  //     update, err := expression.Set(expression.Name("someName"), expression.Name("aName").Minus(expression.Value(10)))
   320  //
   321  // Expression Equivalent:
   322  //
   323  //     expression.Name("aName").Minus(expression.Value(10)))
   324  //     // let :ten be ExpressionAttributeValues represent the value 10
   325  //     "aName - :ten"
   326  func (nb NameBuilder) Minus(rightOperand OperandBuilder) SetValueBuilder {
   327  	return Minus(nb, rightOperand)
   328  }
   329  
   330  // Minus creates a SetValueBuilder to be used in as an argument to Set(). The
   331  // arguments can either be NameBuilders or ValueBuilders. Minus() only supports
   332  // DynamoDB Number types, so the ValueBuilder must be a Number and the
   333  // NameBuilder must specify an item attribute of type Number.
   334  // More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.IncrementAndDecrement
   335  //
   336  // Example:
   337  //
   338  //     // Use Minus() to set the value of item attribute "someName" to 5 - 10
   339  //     update, err := expression.Set(expression.Name("someName"), expression.Value(5).Minus(expression.Value(10)))
   340  //
   341  // Expression Equivalent:
   342  //
   343  //     expression.Value(5).Minus(expression.Value(10))
   344  //     // let :five and :ten be ExpressionAttributeValues for the values 5 and
   345  //     // 10 respectively.
   346  //     ":five - :ten"
   347  func (vb ValueBuilder) Minus(rightOperand OperandBuilder) SetValueBuilder {
   348  	return Minus(vb, rightOperand)
   349  }
   350  
   351  // ListAppend creates a SetValueBuilder to be used in as an argument to Set().
   352  // The arguments can either be NameBuilders or ValueBuilders. ListAppend() only
   353  // supports DynamoDB List types, so the ValueBuilder must be a List and the
   354  // NameBuilder must specify an item attribute of type List.
   355  // More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.UpdatingListElements
   356  //
   357  // Example:
   358  //
   359  //     // Use ListAppend() to set item attribute "someName" to the item
   360  //     // attribute "nameOfList" with "some" and "list" appended to it
   361  //     update, err := expression.Set(expression.Name("someName"), expression.ListAppend(expression.Name("nameOfList"), expression.Value([]string{"some", "list"})))
   362  //
   363  // Expression Equivalent:
   364  //
   365  //     expression.ListAppend(expression.Name("nameOfList"), expression.Value([]string{"some", "list"})
   366  //     // let :list be a ExpressionAttributeValue representing the list
   367  //     // containing "some" and "list".
   368  //     "list_append (nameOfList, :list)"
   369  func ListAppend(leftOperand, rightOperand OperandBuilder) SetValueBuilder {
   370  	return SetValueBuilder{
   371  		leftOperand:  leftOperand,
   372  		rightOperand: rightOperand,
   373  		mode:         listAppendValueMode,
   374  	}
   375  }
   376  
   377  // ListAppend creates a SetValueBuilder to be used in as an argument to Set().
   378  // The arguments can either be NameBuilders or ValueBuilders. ListAppend() only
   379  // supports DynamoDB List types, so the ValueBuilder must be a List and the
   380  // NameBuilder must specify an item attribute of type List.
   381  // More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.UpdatingListElements
   382  //
   383  // Example:
   384  //
   385  //     // Use ListAppend() to set item attribute "someName" to the item
   386  //     // attribute "nameOfList" with "some" and "list" appended to it
   387  //     update, err := expression.Set(expression.Name("someName"), expression.Name("nameOfList").ListAppend(expression.Value([]string{"some", "list"})))
   388  //
   389  // Expression Equivalent:
   390  //
   391  //     expression.Name("nameOfList").ListAppend(expression.Value([]string{"some", "list"})
   392  //     // let :list be a ExpressionAttributeValue representing the list
   393  //     // containing "some" and "list".
   394  //     "list_append (nameOfList, :list)"
   395  func (nb NameBuilder) ListAppend(rightOperand OperandBuilder) SetValueBuilder {
   396  	return ListAppend(nb, rightOperand)
   397  }
   398  
   399  // ListAppend creates a SetValueBuilder to be used in as an argument to Set().
   400  // The arguments can either be NameBuilders or ValueBuilders. ListAppend() only
   401  // supports DynamoDB List types, so the ValueBuilder must be a List and the
   402  // NameBuilder must specify an item attribute of type List.
   403  // More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.UpdatingListElements
   404  //
   405  // Example:
   406  //
   407  //     // Use ListAppend() to set item attribute "someName" to a string list
   408  //     // equal to {"a", "list", "some", "list"}
   409  //     update, err := expression.Set(expression.Name("someName"), expression.Value([]string{"a", "list"}).ListAppend(expression.Value([]string{"some", "list"})))
   410  //
   411  // Expression Equivalent:
   412  //
   413  //     expression.Name([]string{"a", "list"}).ListAppend(expression.Value([]string{"some", "list"})
   414  //     // let :list1 and :list2 be a ExpressionAttributeValue representing the
   415  //     // list {"a", "list"} and {"some", "list"} respectively
   416  //     "list_append (:list1, :list2)"
   417  func (vb ValueBuilder) ListAppend(rightOperand OperandBuilder) SetValueBuilder {
   418  	return ListAppend(vb, rightOperand)
   419  }
   420  
   421  // IfNotExists creates a SetValueBuilder to be used in as an argument to Set().
   422  // The first argument must be a NameBuilder representing the name where the new
   423  // item attribute is created. The second argument can either be a NameBuilder or
   424  // a ValueBuilder. In the case that it is a NameBuilder, the value of the item
   425  // attribute at the name specified becomes the value of the new item attribute.
   426  // More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.PreventingAttributeOverwrites
   427  //
   428  // Example:
   429  //
   430  //     // Use IfNotExists() to set item attribute "someName" to value 5 if
   431  //     // "someName" does not exist yet. (Prevents overwrite)
   432  //     update, err := expression.Set(expression.Name("someName"), expression.IfNotExists(expression.Name("someName"), expression.Value(5)))
   433  //
   434  // Expression Equivalent:
   435  //
   436  //     expression.IfNotExists(expression.Name("someName"), expression.Value(5))
   437  //     // let :five be a ExpressionAttributeValue representing the value 5
   438  //     "if_not_exists (someName, :five)"
   439  func IfNotExists(name NameBuilder, setValue OperandBuilder) SetValueBuilder {
   440  	return SetValueBuilder{
   441  		leftOperand:  name,
   442  		rightOperand: setValue,
   443  		mode:         ifNotExistsValueMode,
   444  	}
   445  }
   446  
   447  // IfNotExists creates a SetValueBuilder to be used in as an argument to Set().
   448  // The first argument must be a NameBuilder representing the name where the new
   449  // item attribute is created. The second argument can either be a NameBuilder or
   450  // a ValueBuilder. In the case that it is a NameBuilder, the value of the item
   451  // attribute at the name specified becomes the value of the new item attribute.
   452  // More information: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.PreventingAttributeOverwrites
   453  //
   454  // Example:
   455  //
   456  //     // Use IfNotExists() to set item attribute "someName" to value 5 if
   457  //     // "someName" does not exist yet. (Prevents overwrite)
   458  //     update, err := expression.Set(expression.Name("someName"), expression.Name("someName").IfNotExists(expression.Value(5)))
   459  //
   460  // Expression Equivalent:
   461  //
   462  //     expression.Name("someName").IfNotExists(expression.Value(5))
   463  //     // let :five be a ExpressionAttributeValue representing the value 5
   464  //     "if_not_exists (someName, :five)"
   465  func (nb NameBuilder) IfNotExists(rightOperand OperandBuilder) SetValueBuilder {
   466  	return IfNotExists(nb, rightOperand)
   467  }
   468  
   469  // BuildOperand creates an Operand struct which are building blocks to DynamoDB
   470  // Expressions. Package methods and functions can establish relationships
   471  // between operands, representing DynamoDB Expressions. The method
   472  // BuildOperand() is called recursively when the Build() method on the type
   473  // Builder is called. BuildOperand() should never be called externally.
   474  // BuildOperand() aliases all strings to avoid stepping over DynamoDB's reserved
   475  // words.
   476  // More information on reserved words at http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html
   477  func (nb NameBuilder) BuildOperand() (Operand, error) {
   478  	if nb.name == "" {
   479  		return Operand{}, newUnsetParameterError("BuildOperand", "NameBuilder")
   480  	}
   481  
   482  	node := exprNode{
   483  		names: []string{},
   484  	}
   485  
   486  	nameSplit := strings.Split(nb.name, ".")
   487  	fmtNames := make([]string, 0, len(nameSplit))
   488  
   489  	for _, word := range nameSplit {
   490  		var substr string
   491  		if word == "" {
   492  			return Operand{}, newInvalidParameterError("BuildOperand", "NameBuilder")
   493  		}
   494  
   495  		if word[len(word)-1] == ']' {
   496  			for j, char := range word {
   497  				if char == '[' {
   498  					substr = word[j:]
   499  					word = word[:j]
   500  					break
   501  				}
   502  			}
   503  		}
   504  
   505  		if word == "" {
   506  			return Operand{}, newInvalidParameterError("BuildOperand", "NameBuilder")
   507  		}
   508  
   509  		// Create a string with special characters that can be substituted later: $p
   510  		node.names = append(node.names, word)
   511  		fmtNames = append(fmtNames, "$n"+substr)
   512  	}
   513  	node.fmtExpr = strings.Join(fmtNames, ".")
   514  	return Operand{
   515  		exprNode: node,
   516  	}, nil
   517  }
   518  
   519  // BuildOperand creates an Operand struct which are building blocks to DynamoDB
   520  // Expressions. Package methods and functions can establish relationships
   521  // between operands, representing DynamoDB Expressions. The method
   522  // BuildOperand() is called recursively when the Build() method on the type
   523  // Builder is called. BuildOperand() should never be called externally.
   524  // BuildOperand() aliases all strings to avoid stepping over DynamoDB's reserved
   525  // words.
   526  // More information on reserved words at http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html
   527  func (vb ValueBuilder) BuildOperand() (Operand, error) {
   528  	var (
   529  		expr *dynamodb.AttributeValue
   530  		err  error
   531  	)
   532  
   533  	switch v := vb.value.(type) {
   534  	case *dynamodb.AttributeValue:
   535  		expr = v
   536  	case dynamodb.AttributeValue:
   537  		expr = &v
   538  	default:
   539  		expr, err = dynamodbattribute.Marshal(vb.value)
   540  		if err != nil {
   541  			return Operand{}, newInvalidParameterError("BuildOperand", "ValueBuilder")
   542  		}
   543  	}
   544  
   545  	// Create a string with special characters that can be substituted later: $v
   546  	operand := Operand{
   547  		exprNode: exprNode{
   548  			values:  []dynamodb.AttributeValue{*expr},
   549  			fmtExpr: "$v",
   550  		},
   551  	}
   552  	return operand, nil
   553  }
   554  
   555  // BuildOperand creates an Operand struct which are building blocks to DynamoDB
   556  // Expressions. Package methods and functions can establish relationships
   557  // between operands, representing DynamoDB Expressions. The method
   558  // BuildOperand() is called recursively when the Build() method on the type
   559  // Builder is called. BuildOperand() should never be called externally.
   560  // BuildOperand() aliases all strings to avoid stepping over DynamoDB's reserved
   561  // words.
   562  // More information on reserved words at http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html
   563  func (sb SizeBuilder) BuildOperand() (Operand, error) {
   564  	operand, err := sb.nameBuilder.BuildOperand()
   565  	operand.exprNode.fmtExpr = "size (" + operand.exprNode.fmtExpr + ")"
   566  
   567  	return operand, err
   568  }
   569  
   570  // BuildOperand creates an Operand struct which are building blocks to DynamoDB
   571  // Expressions. Package methods and functions can establish relationships
   572  // between operands, representing DynamoDB Expressions. The method
   573  // BuildOperand() is called recursively when the Build() method on the type
   574  // Builder is called. BuildOperand() should never be called externally.
   575  // BuildOperand() aliases all strings to avoid stepping over DynamoDB's reserved
   576  // words.
   577  // More information on reserved words at http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html
   578  func (kb KeyBuilder) BuildOperand() (Operand, error) {
   579  	if kb.key == "" {
   580  		return Operand{}, newUnsetParameterError("BuildOperand", "KeyBuilder")
   581  	}
   582  
   583  	ret := Operand{
   584  		exprNode: exprNode{
   585  			names:   []string{kb.key},
   586  			fmtExpr: "$n",
   587  		},
   588  	}
   589  
   590  	return ret, nil
   591  }
   592  
   593  // BuildOperand creates an Operand struct which are building blocks to DynamoDB
   594  // Expressions. Package methods and functions can establish relationships
   595  // between operands, representing DynamoDB Expressions. The method
   596  // BuildOperand() is called recursively when the Build() method on the type
   597  // Builder is called. BuildOperand() should never be called externally.
   598  // BuildOperand() aliases all strings to avoid stepping over DynamoDB's reserved
   599  // words.
   600  // More information on reserved words at http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html
   601  func (svb SetValueBuilder) BuildOperand() (Operand, error) {
   602  	if svb.mode == unsetValue {
   603  		return Operand{}, newUnsetParameterError("BuildOperand", "SetValueBuilder")
   604  	}
   605  
   606  	left, err := svb.leftOperand.BuildOperand()
   607  	if err != nil {
   608  		return Operand{}, err
   609  	}
   610  	leftNode := left.exprNode
   611  
   612  	right, err := svb.rightOperand.BuildOperand()
   613  	if err != nil {
   614  		return Operand{}, err
   615  	}
   616  	rightNode := right.exprNode
   617  
   618  	node := exprNode{
   619  		children: []exprNode{leftNode, rightNode},
   620  	}
   621  
   622  	switch svb.mode {
   623  	case plusValueMode:
   624  		node.fmtExpr = "$c + $c"
   625  	case minusValueMode:
   626  		node.fmtExpr = "$c - $c"
   627  	case listAppendValueMode:
   628  		node.fmtExpr = "list_append($c, $c)"
   629  	case ifNotExistsValueMode:
   630  		node.fmtExpr = "if_not_exists($c, $c)"
   631  	default:
   632  		return Operand{}, fmt.Errorf("build operand error: unsupported mode: %v", svb.mode)
   633  	}
   634  
   635  	return Operand{
   636  		exprNode: node,
   637  	}, nil
   638  }