package expression import ( "fmt" "strings" "github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue" "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" ) // 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{} options ValueBuilderOptions } // ValueBuilderOptions provides the options for how a value is built, and // encoded in the expression. type ValueBuilderOptions struct { // Use functional options to specify how the value will be encoded. If the // value is already an AttributeValue, the EncoderOptions will be ignored. EncoderOptions []func(*attributevalue.EncoderOptions) } // 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 { names []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 { if len(name) == 0 { return NameBuilder{} } return NameBuilder{ names: strings.Split(name, "."), } } // AppendName to adds additional name fields, returning a new NameBuilder. Can // be used to append list indexes and map fields to the Expression attribute // name. // // Leading or trailing dots(`.`) for Names that are not created with // NameNoDotSplit will result in an error when the expression is built. The // dot(`.`) will be added automatically as needed. func (nb NameBuilder) AppendName(field NameBuilder) NameBuilder { names := make([]string, 0, len(nb.names)+len(field.names)) names = append(names, nb.names...) names = append(names, field.names...) // If the name being append starts with a list index it to the name being // appended to. This allows list indexes to be appended to names. If there // is a syntax error in the name, it will be caught when the expression is // built via BuildOperand method. if len(nb.names) != 0 && len(field.names) != 0 { lastLeftName := len(nb.names) - 1 firstRightName := lastLeftName + 1 if v := names[firstRightName]; len(v) > 0 && v[0] == '[' { if end := strings.Index(v, "]"); end != -1 { names[lastLeftName] += v[0 : end+1] names[firstRightName] = v[end+1:] // Remove the name if it is empty after moving the index. if len(names[firstRightName]) == 0 { copy(names[firstRightName:], names[firstRightName+1:]) names[len(names)-1] = "" names = names[:len(names)-1] } } } } return NameBuilder{ names: names, } } // NameNoDotSplit returns a NameBuilder. The argument should represent the // desired item attribute. The name will not be split on dots. The name may end // with square brackets for list indexes. Square brackets will not be // considered a part of the NameLiteral. // // Use NameBuilder.WithField method to add subsequent map field names. // Use NameBuilder.WithListIndex method to add list index to the name. // // See: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.Attributes.html // // Example: // // // Specify a name containing dots, and should not be split. // name := expression.NameLiteral("Top.Level") // // // 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 NameNoDotSplit(name string) NameBuilder { return NameBuilder{ names: []string{name}, } } // Value creates a ValueBuilder and sets its value to the argument. The value // will be marshalled using the attributevalue package, unless it is of // type types.AttributeValue, where it will be used directly. // // Empty slices and maps will be encoded as their respective empty types.AttributeValue // types. If a NULL value is required, pass a dynamodb.AttributeValue, e.g.: // emptyList := &types.AttributeValueMemberNULL{Value: true} // // Example: // // // Use Value() to create a condition expression // condition := expression.Name("foo").Equal(expression.Value(10)) // // Use Value() to set the value of a set expression. // update := Set(expression.Name("greets"), expression.Value(&types.AttributeValueMemberS{Value: "hello"})) func Value(value interface{}) ValueBuilder { return ValueBuilder{ value: value, } } // ValueWithOptions creates a ValueBuilder and sets its value to the argument. The value // will be marshalled using the attributevalue package, unless it is of // type types.AttributeValue, where it will be used directly. // // The ValueBuilderOptions functional options parameter allows you to specify // how the value will be encoded. Including options like AttributeValue // encoding struct tag. If value is already a DynamoDB AttributeValue, // encoding options will have not effect. // // Empty slices and maps will be encoded as their respective empty types.AttributeValue // types. If a NULL value is required, pass a dynamodb.AttributeValue, e.g.: // emptyList := &types.AttributeValueMemberNULL{Value: true} // // Example: // // // Use Value() to create a condition expression // condition := expression.Name("foo").Equal(expression.Value(10)) // // Use Value() to set the value of a set expression. // update := Set(expression.Name("greets"), expression.Value(&types.AttributeValueMemberS{Value: "hello"})) func ValueWithOptions(value interface{}, optFns ...func(*ValueBuilderOptions)) ValueBuilder { var options ValueBuilderOptions for _, fn := range optFns { fn(&options) } return ValueBuilder{ value: value, options: options, } } // 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 len(nb.names) == 0 { return Operand{}, newUnsetParameterError("BuildOperand", "NameBuilder") } node := exprNode{ names: []string{}, } fmtNames := make([]string, 0, len(nb.names)) for _, word := range nb.names { var substr string if word == "" { return Operand{}, newInvalidParameterError("BuildOperand", "NameBuilder") } if idx := strings.Index(word, "]"); idx != -1 && idx != len(word)-1 { 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) { var ( expr types.AttributeValue err error ) switch v := vb.value.(type) { case types.AttributeValueMemberS: expr = &v case types.AttributeValueMemberN: expr = &v case types.AttributeValueMemberB: expr = &v case types.AttributeValueMemberSS: expr = &v case types.AttributeValueMemberNS: expr = &v case types.AttributeValueMemberBS: expr = &v case types.AttributeValueMemberM: expr = &v case types.AttributeValueMemberL: expr = &v case types.AttributeValueMemberNULL: expr = &v case types.AttributeValueMemberBOOL: expr = &v case types.AttributeValue: expr = v default: expr, err = attributevalue.MarshalWithOptions(vb.value, vb.options.EncoderOptions...) 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: []types.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 }