tests/spec: record the pipeline-style updates
An update document may be an *array* of aggregation stages instead of a
document of operators. The pinned crud corpus has five cases, one per command,
and not one of them is a refusal -- so which stages are allowed, what happens
to `_id`, and what an upsert does are all unmeasured there.
23 cases into the existing operator corpus rather than an eighth directory:
this is another shape of update document, and it shares the recorder, the
masking and the README.
Recorded red, 0/23. What it settled:
- **`_id` always survives**, through `$replaceRoot: {newRoot: "$t"}` and
through `$project: {_id: 0}` alike. A stage that sets it to a *different*
value is ImmutableField (66); restating the same one is fine.
- `$match`, `$group`, `$sort` and `$unwind` are real stages refused
specifically here: InvalidOptions (72), "$X is not allowed to be used
within an update". A name that is no stage at all is 40324, and two
stages packed into one array element is 40323.
- `arrayFilters` beside a pipeline is FailedToParse (9).
- an upsert runs the pipeline over the document the filter implies.
Three shapes were authored and removed: `{b: 1, $set: {...}}`, an empty
pipeline, and a pipeline holding a non-document. The driver rejects all three
before they reach a server, so there is nothing to record.
This commit is contained in:
163
tests/spec/operators/sources/pipeline.json
Normal file
163
tests/spec/operators/sources/pipeline.json
Normal file
@@ -0,0 +1,163 @@
|
||||
{
|
||||
"_comment": [
|
||||
"Inputs only. Expectations are measured -- see record.js.",
|
||||
"Pipeline-style updates: an update document that is an *array* of",
|
||||
"aggregation stages rather than a document of operators. The pinned crud",
|
||||
"corpus has five cases, one per command, and none of them is a refusal --",
|
||||
"so which stages are allowed, what happens to `_id`, and what an upsert",
|
||||
"does are all unmeasured there.",
|
||||
"Two shapes were authored and removed: an empty pipeline and an array",
|
||||
"holding a non-document. The driver rejects both before they reach a",
|
||||
"server ('Update document requires atomic operators'), so there is no",
|
||||
"server answer to record."
|
||||
],
|
||||
"documents": [
|
||||
{ "_id": 1, "x": 1, "y": 1, "t": { "u": { "v": 1 } } },
|
||||
{ "_id": 2, "x": 2, "y": 1 }
|
||||
],
|
||||
"cases": [
|
||||
{
|
||||
"description": "$replaceRoot keeps the _id it was given",
|
||||
"operation": "updateOne",
|
||||
"arguments": {
|
||||
"filter": { "_id": 1 },
|
||||
"update": [{ "$replaceRoot": { "newRoot": "$t" } }]
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "$replaceWith is the same stage under its short name",
|
||||
"operation": "updateOne",
|
||||
"arguments": { "filter": { "_id": 1 }, "update": [{ "$replaceWith": "$t" }] }
|
||||
},
|
||||
{
|
||||
"description": "$project keeps the _id it did not mention",
|
||||
"operation": "updateOne",
|
||||
"arguments": { "filter": { "_id": 1 }, "update": [{ "$project": { "x": 1 } }] }
|
||||
},
|
||||
{
|
||||
"description": "$project excluding _id keeps it anyway",
|
||||
"operation": "updateOne",
|
||||
"arguments": { "filter": { "_id": 1 }, "update": [{ "$project": { "_id": 0, "x": 1 } }] }
|
||||
},
|
||||
{
|
||||
"description": "$addFields adds to the document",
|
||||
"operation": "updateOne",
|
||||
"arguments": { "filter": { "_id": 1 }, "update": [{ "$addFields": { "foo": 1 } }] }
|
||||
},
|
||||
{
|
||||
"description": "$set is $addFields under its other name",
|
||||
"operation": "updateOne",
|
||||
"arguments": { "filter": { "_id": 1 }, "update": [{ "$set": { "foo": "$x" } }] }
|
||||
},
|
||||
{
|
||||
"description": "$unset of one field",
|
||||
"operation": "updateOne",
|
||||
"arguments": { "filter": { "_id": 1 }, "update": [{ "$unset": "y" }] }
|
||||
},
|
||||
{
|
||||
"description": "$unset of several fields",
|
||||
"operation": "updateOne",
|
||||
"arguments": { "filter": { "_id": 1 }, "update": [{ "$unset": ["y", "t"] }] }
|
||||
},
|
||||
{
|
||||
"description": "the stages run in order, each on the last one's output",
|
||||
"operation": "updateOne",
|
||||
"arguments": {
|
||||
"filter": { "_id": 1 },
|
||||
"update": [{ "$replaceRoot": { "newRoot": "$t" } }, { "$addFields": { "foo": 1 } }]
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "an expression reads the document the stage was handed",
|
||||
"operation": "updateOne",
|
||||
"arguments": {
|
||||
"filter": { "_id": 1 },
|
||||
"update": [{ "$addFields": { "z": { "$add": ["$x", "$y"] } } }]
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "a stage may restate the _id it already has",
|
||||
"operation": "updateOne",
|
||||
"arguments": { "filter": { "_id": 1 }, "update": [{ "$addFields": { "_id": 1 } }] }
|
||||
},
|
||||
{
|
||||
"description": "a stage may not change the _id",
|
||||
"operation": "updateOne",
|
||||
"arguments": { "filter": { "_id": 1 }, "update": [{ "$addFields": { "_id": 9 } }] }
|
||||
},
|
||||
{
|
||||
"description": "updateMany runs the pipeline on every match",
|
||||
"operation": "updateMany",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"update": [{ "$project": { "x": 1 } }, { "$addFields": { "foo": 1 } }]
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "findOneAndUpdate with a pipeline",
|
||||
"operation": "findOneAndUpdate",
|
||||
"arguments": {
|
||||
"filter": { "_id": 1 },
|
||||
"update": [{ "$project": { "x": 1 } }, { "$addFields": { "foo": 1 } }],
|
||||
"returnDocument": "after"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "an upsert runs the pipeline on the document the filter implies",
|
||||
"documents": [],
|
||||
"operation": "updateOne",
|
||||
"arguments": {
|
||||
"filter": { "k": 1 },
|
||||
"update": [{ "$addFields": { "a": 1 } }],
|
||||
"upsert": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "a pipeline that writes nothing new still reports a match",
|
||||
"operation": "updateOne",
|
||||
"arguments": { "filter": { "_id": 1 }, "update": [{ "$addFields": { "x": 1 } }] }
|
||||
},
|
||||
{
|
||||
"description": "$match is not allowed inside an update",
|
||||
"operation": "updateOne",
|
||||
"arguments": { "filter": { "_id": 1 }, "update": [{ "$match": { "x": 1 } }] }
|
||||
},
|
||||
{
|
||||
"description": "$group is not allowed inside an update",
|
||||
"operation": "updateOne",
|
||||
"arguments": { "filter": { "_id": 1 }, "update": [{ "$group": { "_id": null } }] }
|
||||
},
|
||||
{
|
||||
"description": "$sort is not allowed inside an update",
|
||||
"operation": "updateOne",
|
||||
"arguments": { "filter": { "_id": 1 }, "update": [{ "$sort": { "x": 1 } }] }
|
||||
},
|
||||
{
|
||||
"description": "$unwind is not allowed inside an update",
|
||||
"operation": "updateOne",
|
||||
"arguments": { "filter": { "_id": 1 }, "update": [{ "$unwind": "$t" }] }
|
||||
},
|
||||
{
|
||||
"description": "a stage name that is not a stage at all",
|
||||
"operation": "updateOne",
|
||||
"arguments": { "filter": { "_id": 1 }, "update": [{ "$bogus": {} }] }
|
||||
},
|
||||
{
|
||||
"description": "two stages packed into one array element",
|
||||
"operation": "updateOne",
|
||||
"arguments": {
|
||||
"filter": { "_id": 1 },
|
||||
"update": [{ "$addFields": { "a": 1 }, "$unset": "y" }]
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "arrayFilters alongside a pipeline",
|
||||
"operation": "updateOne",
|
||||
"arguments": {
|
||||
"filter": { "_id": 1 },
|
||||
"update": [{ "$addFields": { "a": 1 } }],
|
||||
"arrayFilters": [{ "i.b": 1 }]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user