update: $mul, $min and $max
Three operators, two shapes. `$mul` joins `$inc` in `op_arith` because they
differ only in the operation; `$min` and `$max` are not numeric operators at
all and get their own.
Measured, and each row is a rule that would have been guessed wrong:
- `{$mul: {gone: 5}}` writes **0**, not 5. An absent field starts from zero
under both operators, which is the identity for one and the annihilator
for the other, and mongod picks zero for both.
- `$min`/`$max` compare in BSON canonical order, so `{$min: {s: 5}}` on
`s: "b"` writes 5 -- a number ranks below a string -- and `{$max: {a: 1}}`
on `a: null` writes 1. An absent field is always written: there is nothing
to be smaller or larger than.
- an int32 product that does not fit widens to int64, the same ladder
`numeric_add` already climbed.
`$inc` changes answer with them: a non-numeric field or operand was
`InvalidUpdate` -> BadValue (2), and mongod answers TypeMismatch (14) with a
different sentence for each side. So two errors rather than one, and `$inc`
gets the codes it should always have had.
numeric.json 0/21 -> 20/21. The one left is `$min` and `$max` on the same
field, which is ConflictingUpdateOperators (40) -- a whole error class this
server does not have yet, and its own commit.
228/228 unit tests.
This commit is contained in:
@@ -4253,6 +4253,25 @@ fn update_refusal(reply: *wire.Reply, err: anyerror, diag: update.Diagnostic) !v
|
||||
"name, found '{s}' and '{s}'",
|
||||
.{ diag.segment, diag.other },
|
||||
)),
|
||||
error.NotNumericField => return reply.put_error(
|
||||
@intFromEnum(ErrorCode.type_mismatch),
|
||||
"TypeMismatch",
|
||||
try std.fmt.allocPrint(
|
||||
arena,
|
||||
"Cannot apply {s} to a value of non-numeric type. The field '{s}' is of " ++
|
||||
"non-numeric type {s}",
|
||||
.{ diag.segment, diag.path, diag.other },
|
||||
),
|
||||
),
|
||||
error.NotNumericOperand => return reply.put_error(
|
||||
@intFromEnum(ErrorCode.type_mismatch),
|
||||
"TypeMismatch",
|
||||
try std.fmt.allocPrint(
|
||||
arena,
|
||||
"Cannot {s} with non-numeric argument at field '{s}'",
|
||||
.{ if (std.mem.eql(u8, diag.segment, "$inc")) "increment" else "multiply", diag.path },
|
||||
),
|
||||
),
|
||||
error.PathNotViable => return reply.put_error(
|
||||
@intFromEnum(ErrorCode.path_not_viable),
|
||||
"PathNotViable",
|
||||
|
||||
Reference in New Issue
Block a user