mirror of
				https://github.com/taigrr/yq
				synced 2025-01-18 04:53:17 -08:00 
			
		
		
		
	Added scalar addition
This commit is contained in:
		
							parent
							
								
									e4d48bbc0d
								
							
						
					
					
						commit
						70a1c60d7b
					
				| @ -1,9 +1,9 @@ | |||||||
| Add behaves differently according to the type of the LHS: | Add behaves differently according to the type of the LHS: | ||||||
| - arrays: concatenate | - arrays: concatenate | ||||||
| - number scalars: arithmetic addition (soon) | - number scalars: arithmetic addition | ||||||
| - string scalars: concatenate (soon) | - string scalars: concatenate | ||||||
| 
 | 
 | ||||||
| Use `+=` as append assign for things like increment. `.a += .x` is equivalent to running `.a |= . + .x`. | Use `+=` as append assign for things like increment. Note that `.a += .x` is equivalent to running `.a = .a + .x`. | ||||||
| 
 | 
 | ||||||
| ## Concatenate and assign arrays | ## Concatenate and assign arrays | ||||||
| Given a sample.yml file of: | Given a sample.yml file of: | ||||||
| @ -131,3 +131,85 @@ b: | |||||||
|   - 4 |   - 4 | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | ## String concatenation | ||||||
|  | Given a sample.yml file of: | ||||||
|  | ```yaml | ||||||
|  | a: cat | ||||||
|  | b: meow | ||||||
|  | ``` | ||||||
|  | then | ||||||
|  | ```bash | ||||||
|  | yq eval '.a = .a + .b' sample.yml | ||||||
|  | ``` | ||||||
|  | will output | ||||||
|  | ```yaml | ||||||
|  | a: catmeow | ||||||
|  | b: meow | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Relative string concatenation | ||||||
|  | Given a sample.yml file of: | ||||||
|  | ```yaml | ||||||
|  | a: cat | ||||||
|  | b: meow | ||||||
|  | ``` | ||||||
|  | then | ||||||
|  | ```bash | ||||||
|  | yq eval '.a += .b' sample.yml | ||||||
|  | ``` | ||||||
|  | will output | ||||||
|  | ```yaml | ||||||
|  | a: catmeow | ||||||
|  | b: meow | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Number addition - float | ||||||
|  | If the lhs or rhs are floats then the expression will be calculated with floats. | ||||||
|  | 
 | ||||||
|  | Given a sample.yml file of: | ||||||
|  | ```yaml | ||||||
|  | a: 3 | ||||||
|  | b: 4.9 | ||||||
|  | ``` | ||||||
|  | then | ||||||
|  | ```bash | ||||||
|  | yq eval '.a = .a + .b' sample.yml | ||||||
|  | ``` | ||||||
|  | will output | ||||||
|  | ```yaml | ||||||
|  | a: 7.9 | ||||||
|  | b: 4.9 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Number addition - int | ||||||
|  | If both the lhs and rhs are ints then the expression will be calculated with ints. | ||||||
|  | 
 | ||||||
|  | Given a sample.yml file of: | ||||||
|  | ```yaml | ||||||
|  | a: 3 | ||||||
|  | b: 4 | ||||||
|  | ``` | ||||||
|  | then | ||||||
|  | ```bash | ||||||
|  | yq eval '.a = .a + .b' sample.yml | ||||||
|  | ``` | ||||||
|  | will output | ||||||
|  | ```yaml | ||||||
|  | a: 7 | ||||||
|  | b: 4 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Increment number | ||||||
|  | Given a sample.yml file of: | ||||||
|  | ```yaml | ||||||
|  | a: 3 | ||||||
|  | ``` | ||||||
|  | then | ||||||
|  | ```bash | ||||||
|  | yq eval '.a += 1' sample.yml | ||||||
|  | ``` | ||||||
|  | will output | ||||||
|  | ```yaml | ||||||
|  | a: 4 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| Add behaves differently according to the type of the LHS: | Add behaves differently according to the type of the LHS: | ||||||
| - arrays: concatenate | - arrays: concatenate | ||||||
| - number scalars: arithmetic addition (soon) | - number scalars: arithmetic addition | ||||||
| - string scalars: concatenate (soon) | - string scalars: concatenate | ||||||
| 
 | 
 | ||||||
| Use `+=` as append assign for things like increment. `.a += .x` is equivalent to running `.a |= . + .x`. | Use `+=` as append assign for things like increment. Note that `.a += .x` is equivalent to running `.a = .a + .x`. | ||||||
|  | |||||||
| @ -4,21 +4,22 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 
 | 
 | ||||||
| 	"container/list" | 	"container/list" | ||||||
|  | 	"strconv" | ||||||
| 
 | 
 | ||||||
| 	yaml "gopkg.in/yaml.v3" | 	yaml "gopkg.in/yaml.v3" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func createSelfAddOp(rhs *PathTreeNode) *PathTreeNode { | func createAddOp(lhs *PathTreeNode, rhs *PathTreeNode) *PathTreeNode { | ||||||
| 	return &PathTreeNode{Operation: &Operation{OperationType: Add}, | 	return &PathTreeNode{Operation: &Operation{OperationType: Add}, | ||||||
| 		Lhs: &PathTreeNode{Operation: &Operation{OperationType: SelfReference}}, | 		Lhs: lhs, | ||||||
| 		Rhs: rhs} | 		Rhs: rhs} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func AddAssignOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) { | func AddAssignOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) { | ||||||
| 	assignmentOp := &Operation{OperationType: Assign} | 	assignmentOp := &Operation{OperationType: Assign} | ||||||
| 	assignmentOp.UpdateAssign = true | 	assignmentOp.UpdateAssign = false | ||||||
| 
 | 
 | ||||||
| 	assignmentOpNode := &PathTreeNode{Operation: assignmentOp, Lhs: pathNode.Lhs, Rhs: createSelfAddOp(pathNode.Rhs)} | 	assignmentOpNode := &PathTreeNode{Operation: assignmentOp, Lhs: pathNode.Lhs, Rhs: createAddOp(pathNode.Lhs, pathNode.Rhs)} | ||||||
| 	return d.GetMatchingNodes(matchingNodes, assignmentOpNode) | 	return d.GetMatchingNodes(matchingNodes, assignmentOpNode) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -63,7 +64,48 @@ func add(d *dataTreeNavigator, lhs *CandidateNode, rhs *CandidateNode) (*Candida | |||||||
| 		target.Node.Tag = "!!seq" | 		target.Node.Tag = "!!seq" | ||||||
| 		target.Node.Content = append(lhsNode.Content, toNodes(rhs)...) | 		target.Node.Content = append(lhsNode.Content, toNodes(rhs)...) | ||||||
| 	case yaml.ScalarNode: | 	case yaml.ScalarNode: | ||||||
| 		return nil, fmt.Errorf("Scalars not yet supported for addition") | 		if rhs.Node.Kind != yaml.ScalarNode { | ||||||
|  | 			return nil, fmt.Errorf("%v (%v) cannot be added to a %v", rhs.Node.Tag, rhs.Path, lhsNode.Tag) | ||||||
|  | 		} | ||||||
|  | 		target.Node.Kind = yaml.ScalarNode | ||||||
|  | 		target.Node.Style = lhsNode.Style | ||||||
|  | 		return addScalars(target, lhsNode, rhs.Node) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return target, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func addScalars(target *CandidateNode, lhs *yaml.Node, rhs *yaml.Node) (*CandidateNode, error) { | ||||||
|  | 
 | ||||||
|  | 	if lhs.Tag == "!!str" { | ||||||
|  | 		target.Node.Tag = "!!str" | ||||||
|  | 		target.Node.Value = lhs.Value + rhs.Value | ||||||
|  | 	} else if lhs.Tag == "!!int" && rhs.Tag == "!!int" { | ||||||
|  | 		lhsNum, err := strconv.Atoi(lhs.Value) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		rhsNum, err := strconv.Atoi(rhs.Value) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		sum := lhsNum + rhsNum | ||||||
|  | 		target.Node.Tag = "!!int" | ||||||
|  | 		target.Node.Value = fmt.Sprintf("%v", sum) | ||||||
|  | 	} else if (lhs.Tag == "!!int" || lhs.Tag == "!!float") && (rhs.Tag == "!!int" || rhs.Tag == "!!float") { | ||||||
|  | 		lhsNum, err := strconv.ParseFloat(lhs.Value, 64) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		rhsNum, err := strconv.ParseFloat(rhs.Value, 64) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		sum := lhsNum + rhsNum | ||||||
|  | 		target.Node.Tag = "!!float" | ||||||
|  | 		target.Node.Value = fmt.Sprintf("%v", sum) | ||||||
|  | 	} else { | ||||||
|  | 		return nil, fmt.Errorf("%v cannot be added to %v", lhs.Tag, rhs.Tag) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return target, nil | 	return target, nil | ||||||
|  | |||||||
| @ -61,6 +61,48 @@ var addOperatorScenarios = []expressionScenario{ | |||||||
| 			"D0, P[], (doc)::{a: [1, 2, 3, 4], b: [3, 4]}\n", | 			"D0, P[], (doc)::{a: [1, 2, 3, 4], b: [3, 4]}\n", | ||||||
| 		}, | 		}, | ||||||
| 	}, | 	}, | ||||||
|  | 	{ | ||||||
|  | 		description: "String concatenation", | ||||||
|  | 		document:    `{a: cat, b: meow}`, | ||||||
|  | 		expression:  `.a = .a + .b`, | ||||||
|  | 		expected: []string{ | ||||||
|  | 			"D0, P[], (doc)::{a: catmeow, b: meow}\n", | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		description: "Relative string concatenation", | ||||||
|  | 		document:    `{a: cat, b: meow}`, | ||||||
|  | 		expression:  `.a += .b`, | ||||||
|  | 		expected: []string{ | ||||||
|  | 			"D0, P[], (doc)::{a: catmeow, b: meow}\n", | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		description:    "Number addition - float", | ||||||
|  | 		subdescription: "If the lhs or rhs are floats then the expression will be calculated with floats.", | ||||||
|  | 		document:       `{a: 3, b: 4.9}`, | ||||||
|  | 		expression:     `.a = .a + .b`, | ||||||
|  | 		expected: []string{ | ||||||
|  | 			"D0, P[], (doc)::{a: 7.9, b: 4.9}\n", | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		description:    "Number addition - int", | ||||||
|  | 		subdescription: "If both the lhs and rhs are ints then the expression will be calculated with ints.", | ||||||
|  | 		document:       `{a: 3, b: 4}`, | ||||||
|  | 		expression:     `.a = .a + .b`, | ||||||
|  | 		expected: []string{ | ||||||
|  | 			"D0, P[], (doc)::{a: 7, b: 4}\n", | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		description: "Increment number", | ||||||
|  | 		document:    `{a: 3}`, | ||||||
|  | 		expression:  `.a += 1`, | ||||||
|  | 		expected: []string{ | ||||||
|  | 			"D0, P[], (doc)::{a: 4}\n", | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestAddOperatorScenarios(t *testing.T) { | func TestAddOperatorScenarios(t *testing.T) { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user