update: $addToSet, $pop and $pullAll
`$addToSet`'s identity is `bson.compare` equality, which is already exactly
mongod's: an int32 `2` and a double `2.0` are one value, and `{a: 1, b: 2}`
and `{b: 2, a: 1}` are two, because `compare_docs` walks the pairs
positionally and tie-breaks on the key. Candidates are checked against the
array as it grows, so a `$each` holding the same value twice adds it once.
`$pullAll` is `$pull`'s neighbour and its opposite: `$pull` takes a predicate,
`$pullAll` takes values compared whole. `{$pull: {t: {a: 1}}}` removes
elements *having* `a: 1`; `{$pullAll: {t: [{a: 1}]}}` removes elements that
*are* `{a: 1}`. Sharing the comparison would have been the natural mistake and
is what the test mutates to check.
`$pop` is the small one, and its refusals are the measured part: an empty
array and an absent field are no-ops, an argument that is not 1 or -1 is
FailedToParse (9), and a non-array field is TypeMismatch (14) -- where the
identical mistake under `$addToSet` and `$pullAll` is BadValue (2). Three
codes for one shape, none of them derivable from the others. `$each` that is
not an array is 14 under `$addToSet` and 2 under `$push`, measured on both.
array-ops.json 2/26 -> 26/26. 234/234 unit tests.
This commit is contained in:
@@ -4272,6 +4272,42 @@ fn update_refusal(reply: *wire.Reply, err: anyerror, diag: update.Diagnostic) !v
|
||||
.{ if (std.mem.eql(u8, diag.segment, "$inc")) "increment" else "multiply", diag.path },
|
||||
),
|
||||
),
|
||||
error.NotAnArrayField => return bad_value(reply, try std.fmt.allocPrint(
|
||||
arena,
|
||||
"Cannot apply {s} to non-array field. Field named '{s}' has non-array type",
|
||||
.{ diag.segment, diag.path },
|
||||
)),
|
||||
error.NotAnArrayPathElement => return reply.put_error(
|
||||
@intFromEnum(ErrorCode.type_mismatch),
|
||||
"TypeMismatch",
|
||||
try std.fmt.allocPrint(
|
||||
arena,
|
||||
"Path '{s}' contains an element of non-array type",
|
||||
.{diag.path},
|
||||
),
|
||||
),
|
||||
// mongod has two sentences here -- "$pop expects 1 or -1, found: 2"
|
||||
// and "Expected a number in: t: \"x\"" -- both code 9, and both about
|
||||
// an argument that is not one of the two values `$pop` takes. One
|
||||
// sentence covering both says the same thing without rendering the
|
||||
// operand, which no formatter here does.
|
||||
error.BadPopArgument => return failed_to_parse(reply, try std.fmt.allocPrint(
|
||||
arena,
|
||||
"$pop expects 1 or -1, at field '{s}'",
|
||||
.{diag.path},
|
||||
)),
|
||||
error.PullAllNeedsArray => return bad_value(reply, try std.fmt.allocPrint(
|
||||
arena,
|
||||
"$pullAll requires an array argument but was given a {s}",
|
||||
.{diag.other},
|
||||
)),
|
||||
// `$push` and `$addToSet` disagree about the code for the identical
|
||||
// mistake: 2 and 14. Measured on both, and not derivable from either.
|
||||
error.BadEach => if (std.mem.eql(u8, diag.segment, "$addToSet")) return reply.put_error(
|
||||
@intFromEnum(ErrorCode.type_mismatch),
|
||||
"TypeMismatch",
|
||||
"The argument to $each in $addToSet must be an array",
|
||||
) else return bad_value(reply, "The argument to $each in $push must be an array"),
|
||||
error.PathNotViable => return reply.put_error(
|
||||
@intFromEnum(ErrorCode.path_not_viable),
|
||||
"PathNotViable",
|
||||
|
||||
Reference in New Issue
Block a user