SERVER-118433 Desugar extensions in $graphLookup doc source and agg stage (#47188)
GitOrigin-RevId: 5dac51c09e6663d4e34f1da1612d9670ec3b801e
This commit is contained in:
parent
8b146a6f57
commit
ef6f2fc7b2
@ -67,7 +67,6 @@ selector:
|
||||
- jstests/with_mongot/e2e/hybridSearch/score_fusion_on_view.js
|
||||
- jstests/with_mongot/e2e/hybridSearch/score_fusion_score_details_test.js
|
||||
- jstests/with_mongot/e2e/hybridSearch/score_multiple_stages.js
|
||||
- jstests/with_mongot/e2e/views/mongot_stage_in_view_definition_graph_lookup.js
|
||||
exclude_with_any_tags:
|
||||
- requires_sharding
|
||||
roots:
|
||||
|
||||
@ -80,7 +80,6 @@ selector:
|
||||
- jstests/with_mongot/e2e/hybridSearch/score_fusion_on_view.js
|
||||
- jstests/with_mongot/e2e/hybridSearch/score_fusion_score_details_test.js
|
||||
- jstests/with_mongot/e2e/hybridSearch/score_multiple_stages.js
|
||||
- jstests/with_mongot/e2e/views/mongot_stage_in_view_definition_graph_lookup.js
|
||||
- jstests/with_mongot/e2e/metadata/meta_dependency_validation.js
|
||||
- jstests/with_mongot/e2e/views/vector_search/unionWith.js
|
||||
- jstests/with_mongot/e2e/hybridSearch/ranked_fusion_verbose_replace_root_test.js
|
||||
|
||||
@ -31,9 +31,6 @@
|
||||
- jstests/with_mongot/e2e/hybridSearch/score_fusion_score_details_test.js
|
||||
- jstests/with_mongot/e2e/hybridSearch/score_multiple_stages.js
|
||||
|
||||
# TODO SERVER-118433: Remove this exclusion.
|
||||
- jstests/with_mongot/e2e/views/mongot_stage_in_view_definition_graph_lookup.js
|
||||
|
||||
# Exclude tests that are incompatible with sharded extension-enabled configuration.
|
||||
# This includes all exclusions from exclude_incompatible_tests plus sharded-only failures.
|
||||
- name: exclude_sharded_incompatible_tests
|
||||
@ -63,9 +60,6 @@
|
||||
- jstests/with_mongot/e2e/hybridSearch/score_fusion_score_details_test.js
|
||||
- jstests/with_mongot/e2e/hybridSearch/score_multiple_stages.js
|
||||
|
||||
# TODO SERVER-118433: Remove this exclusion.
|
||||
- jstests/with_mongot/e2e/views/mongot_stage_in_view_definition_graph_lookup.js
|
||||
|
||||
# TODO SERVER-118499: Remove this exclusion when sortKey is propogated correctly.
|
||||
- jstests/with_mongot/e2e/metadata/meta_dependency_validation.js
|
||||
- jstests/with_mongot/e2e/views/vector_search/unionWith.js
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Test that $graphLookup can run on a view containing a $unionWith stage with an extension stage
|
||||
* in its subpipeline.
|
||||
* Test that $graphLookup can run on views containing extension stages, either directly in the
|
||||
* view definition or within a $unionWith subpipeline.
|
||||
*
|
||||
* @tags: [featureFlagExtensionsAPI]
|
||||
*/
|
||||
@ -33,8 +33,8 @@ const numUsers = users.length;
|
||||
const expectedUsersInView = numUsers - 1;
|
||||
coll.insertMany(users);
|
||||
|
||||
function runGraphLookup(fromViewName, fromViewPipeline) {
|
||||
assert.commandWorked(db.createView(fromViewName, collName, fromViewPipeline));
|
||||
function runGraphLookup(fromViewName, fromViewPipeline, source = collName) {
|
||||
assert.commandWorked(db.createView(fromViewName, source, fromViewPipeline));
|
||||
|
||||
// Sanity check to make sure the view returns what we expect.
|
||||
const view = db[fromViewName];
|
||||
@ -66,6 +66,25 @@ function runGraphLookup(fromViewName, fromViewPipeline) {
|
||||
assert.commandWorked(coll.getDB().runCommand({drop: fromViewName}));
|
||||
}
|
||||
|
||||
describe("$graphLookup with extension stages in view definition", function () {
|
||||
it("should run $graphLookup on a view with a desugar/source stage in definition", function () {
|
||||
runGraphLookup(collName + "_read_n_docs_view", [{$readNDocuments: {numDocs: expectedUsersInView}}]);
|
||||
});
|
||||
|
||||
it("should run $graphLookup on a view with a 'transform' stage in definition", function () {
|
||||
runGraphLookup(collName + "_extension_limit_view", [{$sort: {_id: 1}}, {$extensionLimit: expectedUsersInView}]);
|
||||
});
|
||||
|
||||
it("should run $graphLookup on a nested view with extension stage in inner view definition", function () {
|
||||
const nestedViewName = collName + "_nested_extension_view";
|
||||
assert.commandWorked(
|
||||
db.createView(nestedViewName, collName, [{$readNDocuments: {numDocs: expectedUsersInView}}]),
|
||||
);
|
||||
runGraphLookup(collName + "_nested_view", [], nestedViewName);
|
||||
assert.commandWorked(coll.getDB().runCommand({drop: nestedViewName}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("$graphLookup with $unionWith and extension stages", function () {
|
||||
it("should run $graphLookup on a view with a desugar/source stage in subpipeline", function () {
|
||||
runGraphLookup(collName + "_union_with_read_n_docs_view", [
|
||||
@ -109,5 +128,6 @@ describe("$graphLookup with $unionWith and extension stages", function () {
|
||||
},
|
||||
},
|
||||
]);
|
||||
assert.commandWorked(coll.getDB().runCommand({drop: nestedViewName}));
|
||||
});
|
||||
});
|
||||
@ -549,7 +549,7 @@ std::unique_ptr<mongo::Pipeline> GraphLookUpStage::makePipeline(BSONObj match,
|
||||
_fromExpCtx->setQuerySettingsIfNotPresent(pExpCtx->getQuerySettings());
|
||||
|
||||
std::unique_ptr<mongo::Pipeline> pipeline = mongo::pipeline_factory::makePipeline(
|
||||
_fromPipeline, _fromExpCtx, pipeline_factory::kOptionsMinimal);
|
||||
_fromPipeline, _fromExpCtx, pipeline_factory::kDesugarOnly);
|
||||
try {
|
||||
return pExpCtx->getMongoProcessInterface()->finalizeAndMaybePreparePipelineForExecution(
|
||||
_fromExpCtx,
|
||||
@ -596,7 +596,7 @@ std::unique_ptr<mongo::Pipeline> GraphLookUpStage::makePipeline(BSONObj match,
|
||||
|
||||
// We can now safely optimize and reattempt attaching the cursor source.
|
||||
pipeline = mongo::pipeline_factory::makePipeline(
|
||||
_fromPipeline, _fromExpCtx, pipeline_factory::kOptionsMinimal);
|
||||
_fromPipeline, _fromExpCtx, pipeline_factory::kDesugarOnly);
|
||||
|
||||
return pExpCtx->getMongoProcessInterface()->finalizeAndMaybePreparePipelineForExecution(
|
||||
_fromExpCtx,
|
||||
|
||||
@ -286,12 +286,8 @@ TEST_F(LoadExtensionsTest, LoadMatchTopNDesugarExtensionSucceeds) {
|
||||
|
||||
// Full Parse expansion
|
||||
{
|
||||
auto parsedPipeline = pipeline_factory::makePipeline(pipeline,
|
||||
expCtx,
|
||||
{.optimize = false,
|
||||
.alreadyOptimized = false,
|
||||
.attachCursorSource = false,
|
||||
.desugar = true});
|
||||
auto parsedPipeline =
|
||||
pipeline_factory::makePipeline(pipeline, expCtx, pipeline_factory::kDesugarOnly);
|
||||
ASSERT_EQ(parsedPipeline->size(), 4U);
|
||||
|
||||
auto it = parsedPipeline->getSources().begin();
|
||||
|
||||
@ -108,12 +108,7 @@ protected:
|
||||
static std::vector<BSONObj> desugarAndSerialize(
|
||||
const boost::intrusive_ptr<ExpressionContext>& expCtx, const BSONObj& stageSpec) {
|
||||
std::vector<BSONObj> spec{stageSpec};
|
||||
auto pipe = pipeline_factory::makePipeline(spec,
|
||||
expCtx,
|
||||
{.optimize = false,
|
||||
.alreadyOptimized = false,
|
||||
.attachCursorSource = false,
|
||||
.desugar = true});
|
||||
auto pipe = pipeline_factory::makePipeline(spec, expCtx, pipeline_factory::kDesugarOnly);
|
||||
ASSERT_TRUE(pipe);
|
||||
return pipe->serializeToBson();
|
||||
}
|
||||
|
||||
@ -486,8 +486,8 @@ boost::intrusive_ptr<DocumentSource> DocumentSourceGraphLookUp::clone(
|
||||
void DocumentSourceGraphLookUp::addInvolvedCollections(
|
||||
stdx::unordered_set<NamespaceString>* collectionNames) const {
|
||||
collectionNames->insert(_fromExpCtx->getNamespaceString());
|
||||
auto introspectionPipeline = pipeline_factory::makePipeline(
|
||||
_fromPipeline, _fromExpCtx, pipeline_factory::kOptionsMinimal);
|
||||
auto introspectionPipeline =
|
||||
pipeline_factory::makePipeline(_fromPipeline, _fromExpCtx, pipeline_factory::kDesugarOnly);
|
||||
for (auto&& stage : introspectionPipeline->getSources()) {
|
||||
stage->addInvolvedCollections(collectionNames);
|
||||
}
|
||||
|
||||
@ -470,10 +470,9 @@ Value DocumentSourceUnionWith::serialize(const SerializationOptions& opts) const
|
||||
std::move(recoveredPipeline),
|
||||
_userNss);
|
||||
} else {
|
||||
pipeline_factory::MakePipelineOptions opts = pipeline_factory::kOptionsMinimal;
|
||||
opts.desugar = true;
|
||||
pipeCopy = pipeline_factory::makePipeline(
|
||||
recoveredPipeline, _sharedState->_pipeline->getContext(), opts);
|
||||
pipeCopy = pipeline_factory::makePipeline(recoveredPipeline,
|
||||
_sharedState->_pipeline->getContext(),
|
||||
pipeline_factory::kDesugarOnly);
|
||||
}
|
||||
} else {
|
||||
// The plan does not require reading from the sub-pipeline, so just include the
|
||||
@ -671,12 +670,9 @@ std::unique_ptr<Pipeline> DocumentSourceUnionWith::parsePipelineWithMaybeViewDef
|
||||
src->constraints().isAllowedInUnionPipeline());
|
||||
}
|
||||
};
|
||||
pipeline_factory::MakePipelineOptions opts;
|
||||
opts.attachCursorSource = false;
|
||||
// We will call optimize() when finalizing the pipeline in 'doGetNext()'.
|
||||
opts.optimize = false;
|
||||
auto opts = pipeline_factory::kDesugarOnly;
|
||||
opts.validator = validatorCallback;
|
||||
opts.desugar = true;
|
||||
|
||||
boost::intrusive_ptr<ExpressionContext> subExpCtx = makeCopyForSubPipelineFromExpressionContext(
|
||||
expCtx, resolvedNs.ns, resolvedNs.uuid, userNss);
|
||||
|
||||
@ -58,6 +58,9 @@ struct MakePipelineOptions {
|
||||
static const MakePipelineOptions kOptionsMinimal{
|
||||
.optimize = false, .alreadyOptimized = false, .attachCursorSource = false, .desugar = false};
|
||||
|
||||
static const MakePipelineOptions kDesugarOnly{
|
||||
.optimize = false, .alreadyOptimized = false, .attachCursorSource = false, .desugar = true};
|
||||
|
||||
/**
|
||||
* Factory functions for creating Pipeline objects from various input formats.
|
||||
*
|
||||
|
||||
Loading…
Reference in New Issue
Block a user