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

     1  //go:build go1.7
     2  // +build go1.7
     3  
     4  package expression
     5  
     6  import (
     7  	"reflect"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/aavshr/aws-sdk-go/aws"
    12  	"github.com/aavshr/aws-sdk-go/service/dynamodb"
    13  )
    14  
    15  // updateErrorMode will help with error cases and checking error types
    16  type updateErrorMode string
    17  
    18  const (
    19  	noUpdateError             updateErrorMode = ""
    20  	invalidUpdateOperand                      = "BuildOperand error"
    21  	unsetSetValue                             = "unset parameter: SetValueBuilder"
    22  	unsetUpdate                               = "unset parameter: UpdateBuilder"
    23  	emptyOperationBuilderList                 = "operationBuilder list is empty"
    24  )
    25  
    26  func TestBuildOperation(t *testing.T) {
    27  	cases := []struct {
    28  		name     string
    29  		input    operationBuilder
    30  		expected exprNode
    31  		err      updateErrorMode
    32  	}{
    33  		{
    34  			name: "set operation",
    35  			input: operationBuilder{
    36  				name:  Name("foo"),
    37  				value: Value(5),
    38  				mode:  setOperation,
    39  			},
    40  			expected: exprNode{
    41  				children: []exprNode{
    42  					{
    43  						names:   []string{"foo"},
    44  						fmtExpr: "$n",
    45  					},
    46  					{
    47  						values: []dynamodb.AttributeValue{
    48  							{
    49  								N: aws.String("5"),
    50  							},
    51  						},
    52  						fmtExpr: "$v",
    53  					},
    54  				},
    55  				fmtExpr: "$c = $c",
    56  			},
    57  		},
    58  		{
    59  			name: "add operation",
    60  			input: operationBuilder{
    61  				name:  Name("foo"),
    62  				value: Value(5),
    63  				mode:  addOperation,
    64  			},
    65  			expected: exprNode{
    66  				children: []exprNode{
    67  					{
    68  						names:   []string{"foo"},
    69  						fmtExpr: "$n",
    70  					},
    71  					{
    72  						values: []dynamodb.AttributeValue{
    73  							{
    74  								N: aws.String("5"),
    75  							},
    76  						},
    77  						fmtExpr: "$v",
    78  					},
    79  				},
    80  				fmtExpr: "$c $c",
    81  			},
    82  		},
    83  		{
    84  			name: "remove operation",
    85  			input: operationBuilder{
    86  				name: Name("foo"),
    87  				mode: removeOperation,
    88  			},
    89  			expected: exprNode{
    90  				children: []exprNode{
    91  					{
    92  						names:   []string{"foo"},
    93  						fmtExpr: "$n",
    94  					},
    95  				},
    96  				fmtExpr: "$c",
    97  			},
    98  		},
    99  		{
   100  			name: "invalid operand",
   101  			input: operationBuilder{
   102  				name: Name(""),
   103  				mode: removeOperation,
   104  			},
   105  			err: invalidUpdateOperand,
   106  		},
   107  	}
   108  	for _, c := range cases {
   109  		t.Run(c.name, func(t *testing.T) {
   110  			actual, err := c.input.buildOperation()
   111  			if c.err != noUpdateError {
   112  				if err == nil {
   113  					t.Errorf("expect error %q, got no error", c.err)
   114  				} else {
   115  					if e, a := string(c.err), err.Error(); !strings.Contains(a, e) {
   116  						t.Errorf("expect %q error message to be in %q", e, a)
   117  					}
   118  				}
   119  			} else {
   120  				if err != nil {
   121  					t.Errorf("expect no error, got unexpected Error %q", err)
   122  				}
   123  
   124  				if e, a := c.expected, actual; !reflect.DeepEqual(a, e) {
   125  					t.Errorf("expect %v, got %v", e, a)
   126  				}
   127  			}
   128  		})
   129  	}
   130  }
   131  
   132  func TestUpdateTree(t *testing.T) {
   133  	cases := []struct {
   134  		name         string
   135  		input        UpdateBuilder
   136  		expectedNode exprNode
   137  		err          updateErrorMode
   138  	}{
   139  		{
   140  			name:  "set update",
   141  			input: Set(Name("foo"), Value(5)),
   142  			expectedNode: exprNode{
   143  				children: []exprNode{
   144  					{
   145  						children: []exprNode{
   146  							{
   147  								children: []exprNode{
   148  									{
   149  										names:   []string{"foo"},
   150  										fmtExpr: "$n",
   151  									},
   152  									{
   153  										values: []dynamodb.AttributeValue{
   154  											{
   155  												N: aws.String("5"),
   156  											},
   157  										},
   158  										fmtExpr: "$v",
   159  									},
   160  								},
   161  								fmtExpr: "$c = $c",
   162  							},
   163  						},
   164  						fmtExpr: "$c",
   165  					},
   166  				},
   167  				fmtExpr: "SET $c\n",
   168  			},
   169  		},
   170  		{
   171  			name:  "remove update",
   172  			input: Remove(Name("foo")),
   173  			expectedNode: exprNode{
   174  				children: []exprNode{
   175  					{
   176  						children: []exprNode{
   177  							{
   178  								children: []exprNode{
   179  									{
   180  										names:   []string{"foo"},
   181  										fmtExpr: "$n",
   182  									},
   183  								},
   184  								fmtExpr: "$c",
   185  							},
   186  						},
   187  						fmtExpr: "$c",
   188  					},
   189  				},
   190  				fmtExpr: "REMOVE $c\n",
   191  			},
   192  		},
   193  		{
   194  			name:  "add update",
   195  			input: Add(Name("foo"), Value(5)),
   196  			expectedNode: exprNode{
   197  				children: []exprNode{
   198  					{
   199  						children: []exprNode{
   200  							{
   201  								children: []exprNode{
   202  									{
   203  										names:   []string{"foo"},
   204  										fmtExpr: "$n",
   205  									},
   206  									{
   207  										values: []dynamodb.AttributeValue{
   208  											{
   209  												N: aws.String("5"),
   210  											},
   211  										},
   212  										fmtExpr: "$v",
   213  									},
   214  								},
   215  								fmtExpr: "$c $c",
   216  							},
   217  						},
   218  						fmtExpr: "$c",
   219  					},
   220  				},
   221  				fmtExpr: "ADD $c\n",
   222  			},
   223  		},
   224  		{
   225  			name:  "delete update",
   226  			input: Delete(Name("foo"), Value(5)),
   227  			expectedNode: exprNode{
   228  				children: []exprNode{
   229  					{
   230  						children: []exprNode{
   231  							{
   232  								children: []exprNode{
   233  									{
   234  										names:   []string{"foo"},
   235  										fmtExpr: "$n",
   236  									},
   237  									{
   238  										values: []dynamodb.AttributeValue{
   239  											{
   240  												N: aws.String("5"),
   241  											},
   242  										},
   243  										fmtExpr: "$v",
   244  									},
   245  								},
   246  								fmtExpr: "$c $c",
   247  							},
   248  						},
   249  						fmtExpr: "$c",
   250  					},
   251  				},
   252  				fmtExpr: "DELETE $c\n",
   253  			},
   254  		},
   255  		{
   256  			name:  "multiple sets",
   257  			input: Set(Name("foo"), Value(5)).Set(Name("bar"), Value(6)).Set(Name("baz"), Name("qux")),
   258  			expectedNode: exprNode{
   259  				fmtExpr: "SET $c\n",
   260  				children: []exprNode{
   261  					{
   262  						fmtExpr: "$c, $c, $c",
   263  						children: []exprNode{
   264  							{
   265  								fmtExpr: "$c = $c",
   266  								children: []exprNode{
   267  									{
   268  										fmtExpr: "$n",
   269  										names:   []string{"foo"},
   270  									},
   271  									{
   272  										fmtExpr: "$v",
   273  										values: []dynamodb.AttributeValue{
   274  											{
   275  												N: aws.String("5"),
   276  											},
   277  										},
   278  									},
   279  								},
   280  							},
   281  							{
   282  								fmtExpr: "$c = $c",
   283  								children: []exprNode{
   284  									{
   285  										fmtExpr: "$n",
   286  										names:   []string{"bar"},
   287  									},
   288  									{
   289  										fmtExpr: "$v",
   290  										values: []dynamodb.AttributeValue{
   291  											{
   292  												N: aws.String("6"),
   293  											},
   294  										},
   295  									},
   296  								},
   297  							},
   298  							{
   299  								fmtExpr: "$c = $c",
   300  								children: []exprNode{
   301  									{
   302  										fmtExpr: "$n",
   303  										names:   []string{"baz"},
   304  									},
   305  									{
   306  										fmtExpr: "$n",
   307  										names:   []string{"qux"},
   308  									},
   309  								},
   310  							},
   311  						},
   312  					},
   313  				},
   314  			},
   315  		},
   316  		{
   317  			name:  "compound update",
   318  			input: Add(Name("foo"), Value(5)).Set(Name("foo"), Value(5)).Delete(Name("foo"), Value(5)).Remove(Name("foo")),
   319  			expectedNode: exprNode{
   320  				children: []exprNode{
   321  					{
   322  						children: []exprNode{
   323  							{
   324  								children: []exprNode{
   325  									{
   326  										names:   []string{"foo"},
   327  										fmtExpr: "$n",
   328  									},
   329  									{
   330  										values: []dynamodb.AttributeValue{
   331  											{
   332  												N: aws.String("5"),
   333  											},
   334  										},
   335  										fmtExpr: "$v",
   336  									},
   337  								},
   338  								fmtExpr: "$c $c",
   339  							},
   340  						},
   341  						fmtExpr: "$c",
   342  					},
   343  					{
   344  						children: []exprNode{
   345  							{
   346  								children: []exprNode{
   347  									{
   348  										names:   []string{"foo"},
   349  										fmtExpr: "$n",
   350  									},
   351  									{
   352  										values: []dynamodb.AttributeValue{
   353  											{
   354  												N: aws.String("5"),
   355  											},
   356  										},
   357  										fmtExpr: "$v",
   358  									},
   359  								},
   360  								fmtExpr: "$c $c",
   361  							},
   362  						},
   363  						fmtExpr: "$c",
   364  					},
   365  					{
   366  						children: []exprNode{
   367  							{
   368  								children: []exprNode{
   369  									{
   370  										names:   []string{"foo"},
   371  										fmtExpr: "$n",
   372  									},
   373  								},
   374  								fmtExpr: "$c",
   375  							},
   376  						},
   377  						fmtExpr: "$c",
   378  					},
   379  					{
   380  						children: []exprNode{
   381  							{
   382  								children: []exprNode{
   383  									{
   384  										names:   []string{"foo"},
   385  										fmtExpr: "$n",
   386  									},
   387  									{
   388  										values: []dynamodb.AttributeValue{
   389  											{
   390  												N: aws.String("5"),
   391  											},
   392  										},
   393  										fmtExpr: "$v",
   394  									},
   395  								},
   396  								fmtExpr: "$c = $c",
   397  							},
   398  						},
   399  						fmtExpr: "$c",
   400  					},
   401  				},
   402  				fmtExpr: "ADD $c\nDELETE $c\nREMOVE $c\nSET $c\n",
   403  			},
   404  		},
   405  		{
   406  			name:  "empty UpdateBuilder",
   407  			input: UpdateBuilder{},
   408  			err:   unsetUpdate,
   409  		},
   410  	}
   411  	for _, c := range cases {
   412  		t.Run(c.name, func(t *testing.T) {
   413  			actual, err := c.input.buildTree()
   414  			if c.err != noUpdateError {
   415  				if err == nil {
   416  					t.Errorf("expect error %q, got no error", c.err)
   417  				} else {
   418  					if e, a := string(c.err), err.Error(); !strings.Contains(a, e) {
   419  						t.Errorf("expect %q error message to be in %q", e, a)
   420  					}
   421  				}
   422  			} else {
   423  				if err != nil {
   424  					t.Errorf("expect no error, got unexpected Error %q", err)
   425  				}
   426  
   427  				if e, a := c.expectedNode, actual; !reflect.DeepEqual(a, e) {
   428  					t.Errorf("expect %v, got %v", e, a)
   429  				}
   430  			}
   431  		})
   432  	}
   433  }
   434  
   435  func TestSetValueBuilder(t *testing.T) {
   436  	cases := []struct {
   437  		name     string
   438  		input    SetValueBuilder
   439  		expected exprNode
   440  		err      updateErrorMode
   441  	}{
   442  		{
   443  			name:  "name plus name",
   444  			input: Name("foo").Plus(Name("bar")),
   445  			expected: exprNode{
   446  				children: []exprNode{
   447  					{
   448  						names:   []string{"foo"},
   449  						fmtExpr: "$n",
   450  					},
   451  					{
   452  						names:   []string{"bar"},
   453  						fmtExpr: "$n",
   454  					},
   455  				},
   456  				fmtExpr: "$c + $c",
   457  			},
   458  		},
   459  		{
   460  			name:  "name minus name",
   461  			input: Name("foo").Minus(Name("bar")),
   462  			expected: exprNode{
   463  				children: []exprNode{
   464  					{
   465  						names:   []string{"foo"},
   466  						fmtExpr: "$n",
   467  					},
   468  					{
   469  						names:   []string{"bar"},
   470  						fmtExpr: "$n",
   471  					},
   472  				},
   473  				fmtExpr: "$c - $c",
   474  			},
   475  		},
   476  		{
   477  			name:  "list append name and name",
   478  			input: Name("foo").ListAppend(Name("bar")),
   479  			expected: exprNode{
   480  				children: []exprNode{
   481  					{
   482  						names:   []string{"foo"},
   483  						fmtExpr: "$n",
   484  					},
   485  					{
   486  						names:   []string{"bar"},
   487  						fmtExpr: "$n",
   488  					},
   489  				},
   490  				fmtExpr: "list_append($c, $c)",
   491  			},
   492  		},
   493  		{
   494  			name:  "if not exists name and name",
   495  			input: Name("foo").IfNotExists(Name("bar")),
   496  			expected: exprNode{
   497  				children: []exprNode{
   498  					{
   499  						names:   []string{"foo"},
   500  						fmtExpr: "$n",
   501  					},
   502  					{
   503  						names:   []string{"bar"},
   504  						fmtExpr: "$n",
   505  					},
   506  				},
   507  				fmtExpr: "if_not_exists($c, $c)",
   508  			},
   509  		},
   510  		{
   511  			name:  "value plus name",
   512  			input: Value(5).Plus(Name("bar")),
   513  			expected: exprNode{
   514  				children: []exprNode{
   515  					{
   516  						values: []dynamodb.AttributeValue{
   517  							{
   518  								N: aws.String("5"),
   519  							},
   520  						},
   521  						fmtExpr: "$v",
   522  					},
   523  					{
   524  						names:   []string{"bar"},
   525  						fmtExpr: "$n",
   526  					},
   527  				},
   528  				fmtExpr: "$c + $c",
   529  			},
   530  		},
   531  		{
   532  			name:  "value minus name",
   533  			input: Value(5).Minus(Name("bar")),
   534  			expected: exprNode{
   535  				children: []exprNode{
   536  					{
   537  						values: []dynamodb.AttributeValue{
   538  							{
   539  								N: aws.String("5"),
   540  							},
   541  						},
   542  						fmtExpr: "$v",
   543  					},
   544  					{
   545  						names:   []string{"bar"},
   546  						fmtExpr: "$n",
   547  					},
   548  				},
   549  				fmtExpr: "$c - $c",
   550  			},
   551  		},
   552  		{
   553  			name:  "list append list and name",
   554  			input: Value([]int{1, 2, 3}).ListAppend(Name("bar")),
   555  			expected: exprNode{
   556  				children: []exprNode{
   557  					{
   558  						values: []dynamodb.AttributeValue{
   559  							{
   560  								L: []*dynamodb.AttributeValue{
   561  									{
   562  										N: aws.String("1"),
   563  									},
   564  									{
   565  										N: aws.String("2"),
   566  									},
   567  									{
   568  										N: aws.String("3"),
   569  									},
   570  								},
   571  							},
   572  						},
   573  						fmtExpr: "$v",
   574  					},
   575  					{
   576  						names:   []string{"bar"},
   577  						fmtExpr: "$n",
   578  					},
   579  				},
   580  				fmtExpr: "list_append($c, $c)",
   581  			},
   582  		},
   583  		{
   584  			name:  "unset SetValueBuilder",
   585  			input: SetValueBuilder{},
   586  			err:   unsetSetValue,
   587  		},
   588  		{
   589  			name:  "invalid operand error",
   590  			input: Name("").Plus(Name("foo")),
   591  			err:   invalidUpdateOperand,
   592  		},
   593  		{
   594  			name:  "invalid operand error",
   595  			input: Name("foo").Plus(Name("")),
   596  			err:   invalidUpdateOperand,
   597  		},
   598  	}
   599  	for _, c := range cases {
   600  		t.Run(c.name, func(t *testing.T) {
   601  			actual, err := c.input.BuildOperand()
   602  			if c.err != noUpdateError {
   603  				if err == nil {
   604  					t.Errorf("expect error %q, got no error", c.err)
   605  				} else {
   606  					if e, a := string(c.err), err.Error(); !strings.Contains(a, e) {
   607  						t.Errorf("expect %q error message to be in %q", e, a)
   608  					}
   609  				}
   610  			} else {
   611  				if err != nil {
   612  					t.Errorf("expect no error, got unexpected Error %q", err)
   613  				}
   614  
   615  				if e, a := c.expected, actual.exprNode; !reflect.DeepEqual(a, e) {
   616  					t.Errorf("expect %v, got %v", e, a)
   617  				}
   618  			}
   619  		})
   620  	}
   621  }
   622  
   623  func TestUpdateBuildChildNodes(t *testing.T) {
   624  	cases := []struct {
   625  		name     string
   626  		input    []operationBuilder
   627  		expected exprNode
   628  		err      updateErrorMode
   629  	}{
   630  		{
   631  			name: "set operand builder",
   632  			input: []operationBuilder{
   633  				{
   634  					mode: setOperation,
   635  					name: NameBuilder{
   636  						name: "foo",
   637  					},
   638  					value: ValueBuilder{
   639  						value: 5,
   640  					},
   641  				},
   642  				{
   643  					mode: setOperation,
   644  					name: NameBuilder{
   645  						name: "bar",
   646  					},
   647  					value: ValueBuilder{
   648  						value: 6,
   649  					},
   650  				},
   651  				{
   652  					mode: setOperation,
   653  					name: NameBuilder{
   654  						name: "baz",
   655  					},
   656  					value: ValueBuilder{
   657  						value: 7,
   658  					},
   659  				},
   660  				{
   661  					mode: setOperation,
   662  					name: NameBuilder{
   663  						name: "qux",
   664  					},
   665  					value: ValueBuilder{
   666  						value: 8,
   667  					},
   668  				},
   669  			},
   670  			expected: exprNode{
   671  				fmtExpr: "$c, $c, $c, $c",
   672  				children: []exprNode{
   673  					{
   674  						fmtExpr: "$c = $c",
   675  						children: []exprNode{
   676  							{
   677  								fmtExpr: "$n",
   678  								names:   []string{"foo"},
   679  							},
   680  							{
   681  								fmtExpr: "$v",
   682  								values: []dynamodb.AttributeValue{
   683  									{
   684  										N: aws.String("5"),
   685  									},
   686  								},
   687  							},
   688  						},
   689  					},
   690  					{
   691  						fmtExpr: "$c = $c",
   692  						children: []exprNode{
   693  							{
   694  								fmtExpr: "$n",
   695  								names:   []string{"bar"},
   696  							},
   697  							{
   698  								fmtExpr: "$v",
   699  								values: []dynamodb.AttributeValue{
   700  									{
   701  										N: aws.String("6"),
   702  									},
   703  								},
   704  							},
   705  						},
   706  					},
   707  					{
   708  						fmtExpr: "$c = $c",
   709  						children: []exprNode{
   710  							{
   711  								fmtExpr: "$n",
   712  								names:   []string{"baz"},
   713  							},
   714  							{
   715  								fmtExpr: "$v",
   716  								values: []dynamodb.AttributeValue{
   717  									{
   718  										N: aws.String("7"),
   719  									},
   720  								},
   721  							},
   722  						},
   723  					},
   724  					{
   725  						fmtExpr: "$c = $c",
   726  						children: []exprNode{
   727  							{
   728  								fmtExpr: "$n",
   729  								names:   []string{"qux"},
   730  							},
   731  							{
   732  								fmtExpr: "$v",
   733  								values: []dynamodb.AttributeValue{
   734  									{
   735  										N: aws.String("8"),
   736  									},
   737  								},
   738  							},
   739  						},
   740  					},
   741  				},
   742  			},
   743  		},
   744  		{
   745  			name:  "empty operationBuilder list",
   746  			input: []operationBuilder{},
   747  			err:   emptyOperationBuilderList,
   748  		},
   749  	}
   750  	for _, c := range cases {
   751  		t.Run(c.name, func(t *testing.T) {
   752  			actual, err := buildChildNodes(c.input)
   753  			if c.err != noUpdateError {
   754  				if err == nil {
   755  					t.Errorf("expect error %q, got no error", c.err)
   756  				} else {
   757  					if e, a := string(c.err), err.Error(); !strings.Contains(a, e) {
   758  						t.Errorf("expect %q error message to be in %q", e, a)
   759  					}
   760  				}
   761  			} else {
   762  				if err != nil {
   763  					t.Errorf("expect no error, got unexpected Error %q", err)
   764  				}
   765  
   766  				if e, a := c.expected, actual; !reflect.DeepEqual(a, e) {
   767  					t.Errorf("expect %v, got %v", e, a)
   768  				}
   769  			}
   770  		})
   771  	}
   772  }