SERVER-125693 Refactor new base field logic (#53196)

GitOrigin-RevId: 749e35a6ee4589881cd881d573e537656c0ee88d
This commit is contained in:
Vesko Karaganev 2026-05-07 15:35:28 +02:00 committed by MongoDB Bot
parent 1d4ffa7619
commit 3c5dfe63ec
2 changed files with 44 additions and 12 deletions

View File

@ -759,18 +759,8 @@ private:
// updated embedded scope.
auto embeddedScope = _scopes.getNextId();
newBaseField = _fields.append(Field{scope, embeddedScope});
auto parentEmbeddedScope =
existingBaseField ? _fields[existingBaseField].embeddedScope : ScopeId::none();
// Where unknown subfields originate:
// - no previous field -> base collection.
// - previous field's scope is exhaustive -> inherit it.
// - previous field is a leaf in a non-exhaustive scope -> this new scope.
auto exhaustiveEmbeddedScope = existingBaseField
? _scopes[_fields[existingBaseField].declaringScope].exhaustiveScope
: ScopeId::none();
if (existingBaseField && !parentEmbeddedScope && !exhaustiveEmbeddedScope) {
exhaustiveEmbeddedScope = embeddedScope;
}
auto [exhaustiveEmbeddedScope, parentEmbeddedScope] =
resolveNewBaseFieldScopes(existingBaseField, embeddedScope);
if (parentEmbeddedScope) {
// The new field depends on the previous field, since it inherits paths.
_fields[newBaseField].dependencies.insert(existingBaseField);
@ -792,6 +782,36 @@ private:
return newBaseField;
}
/**
* Returns the ScopeIds for a new base field.
* 'existingBaseField' is the result of looking up the base field.
* 'embeddedScope' is the ScopeId for the new scope that will be created for the base field.
*/
std::pair<ScopeId, ScopeId> resolveNewBaseFieldScopes(FieldId existingBaseField,
ScopeId embeddedScope) const {
auto parentEmbeddedScope =
existingBaseField ? _fields[existingBaseField].embeddedScope : ScopeId::none();
// Where unknown subfields originate:
auto exhaustiveEmbeddedScope = [&]() {
if (!existingBaseField) {
// No previous field -> base collection.
return ScopeId::none();
}
if (auto previousExhaustiveScope =
_scopes[_fields[existingBaseField].declaringScope].exhaustiveScope) {
// Previous field's scope is exhaustive -> inherit it.
return previousExhaustiveScope;
}
if (!parentEmbeddedScope) {
// Previous field is a leaf in a non-exhaustive scope -> this new scope
return embeddedScope;
}
// TODO(SERVER-126001): We should not return none here.
return ScopeId::none();
}();
return {exhaustiveEmbeddedScope, parentEmbeddedScope};
}
/**
* Includes the field from the parent scope into the given scope.
* This has the semantics of an inclusion projection.

View File

@ -1277,6 +1277,18 @@ TEST_F(PipelineDependencyGraphTest, SetFieldThenIncludeDottedPath) {
});
}
TEST_F(PipelineDependencyGraphTest, DottedPathAfterBaseField) {
setPipeline(
"[{$set: { a: 1 }},"
"{$set: { 'a.a': 1 }},"
"{$set: { 'a.b.a': 1 }}]");
runTest([&] {
// TODO(SERVER-126001): a.x was modified by the first stage
ASSERT_EQUALS(graph->getDeclaringStage(nullptr, "a.x"), nullptr) << graph->toDebugString();
});
}
TEST_F(PipelineDependencyGraphTest, ComplexPathsMultiple) {
setPipeline(
"[{$set: { a: 1, b: 1, 'c.c': 1 }},"