Skip to content

Commit

Permalink
Fix $mul operator handling dot notation (#2094)
Browse files Browse the repository at this point in the history
Closes #1744.
  • Loading branch information
Dmitry authored Mar 3, 2023
1 parent 1f076a5 commit 3c953af
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 15 deletions.
5 changes: 5 additions & 0 deletions integration/shareddata/composites.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ var Composites = &Values[string]{
{"42", "foo"},
{"foo", int32(42)},
},
"document-composite-numerical-field-name": bson.D{
{"foo", int32(42)},
{"42", "foo"},
{"array", bson.D{{"42", int32(42)}}},
},
"document-null": bson.D{{"foo", nil}},
"document-empty": bson.D{},

Expand Down
16 changes: 7 additions & 9 deletions integration/update_field_compat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1202,17 +1202,15 @@ func TestUpdateFieldCompatMul(t *testing.T) {
"DotNotationMissingField": {
update: bson.D{{"$mul", bson.D{{"v..", int32(45)}}}},
resultType: emptyResult,
skip: "https://github.com/FerretDB/FerretDB/issues/1744",
},
"DotNotationNegativeIndex": {
update: bson.D{{"$mul", bson.D{{"v.-1.bar", int32(45)}}}},
resultType: emptyResult,
skip: "https://github.com/FerretDB/FerretDB/issues/2050",
},
"DotNotationIndexExceedsArrayLength": {
update: bson.D{{"$mul", bson.D{{"v.100.bar", int32(45)}}}},
resultType: emptyResult,
skip: "https://github.com/FerretDB/FerretDB/issues/1744",
update: bson.D{{"$mul", bson.D{{"v.100.bar", int32(45)}}}},
},
"DotNotationFieldNumericName": {
update: bson.D{{"$mul", bson.D{{"v.array.42", int32(42)}}}},
},
"DotNotationNegativeIndex": {
update: bson.D{{"$mul", bson.D{{"v.array.-1", int32(42)}}}},
},
}

Expand Down
16 changes: 15 additions & 1 deletion internal/handlers/common/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,21 @@ func processMulFieldExpression(doc *types.Document, updateV any) (bool, error) {

path, err = types.NewPathFromString(mulKey)
if err != nil {
return false, lazyerrors.Error(err)
var pathErr *types.DocumentPathError

if errors.As(err, &pathErr) {
switch pathErr.Code() {
case types.ErrDocumentPathEmptyKey:
return false, commonerrors.NewWriteErrorMsg(
commonerrors.ErrEmptyName,
fmt.Sprintf("Cannot apply $mul to a value of non-numeric type. "+
"{_id: %s} has the field '%s' of non-numeric type object",
must.NotFail(doc.Get("_id")),
mulKey,
),
)
}
}
}

if !doc.HasByPath(path) {
Expand Down
9 changes: 4 additions & 5 deletions internal/types/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package types

import (
"errors"
"fmt"
"math"
"strconv"
Expand All @@ -23,7 +24,6 @@ import (

"golang.org/x/exp/slices"

"github.com/FerretDB/FerretDB/internal/util/lazyerrors"
"github.com/FerretDB/FerretDB/internal/util/must"
)

Expand All @@ -41,6 +41,8 @@ const (
ErrDocumentPathIndexOutOfBound
// ErrDocumentPathCannotCreateField indicates that it's impossible to create a specific field.
ErrDocumentPathCannotCreateField
// ErrDocumentPathEmptyKey indicates that provided path contains empty key.
ErrDocumentPathEmptyKey
)

// DocumentPathError describes an error that could occur on document path related operations.
Expand Down Expand Up @@ -84,13 +86,10 @@ func NewPathFromString(s string) (Path, error) {
var res Path

path := strings.Split(s, ".")
if len(path) == 0 {
return res, lazyerrors.New("empty path")
}

for _, s := range path {
if s == "" {
return res, lazyerrors.New("path element must not be empty")
return res, newDocumentPathError(ErrDocumentPathEmptyKey, errors.New("path element must not be empty"))
}
}

Expand Down

0 comments on commit 3c953af

Please sign in to comment.