std::unique_ptr<ParsedAggregationProjection> ParsedAggregationProjection::create(
    const BSONObj& spec) {
    // Check for any conflicting specifications, and determine the type of the projection.
    auto projectionType = ProjectSpecTypeParser::parse(spec);

    // We can't use make_unique() here, since the branches have different types.
    std::unique_ptr<ParsedAggregationProjection> parsedProject(
        projectionType == ProjectionType::kInclusion
            ? static_cast<ParsedAggregationProjection*>(new ParsedInclusionProjection())
            : static_cast<ParsedAggregationProjection*>(new ParsedExclusionProjection()));

    // Actually parse the specification.
    parsedProject->parse(spec);
    return parsedProject;
}
std::unique_ptr<ParsedAggregationProjection> ParsedAggregationProjection::create(
    const boost::intrusive_ptr<ExpressionContext>& expCtx, const BSONObj& spec) {
    // Check that the specification was valid. Status returned is unspecific because validate()
    // is used by the $addFields stage as well as $project.
    // If there was an error, uassert with a $project-specific message.
    ProjectionSpecValidator::uassertValid(spec, "$project");

    // Check for any conflicting specifications, and determine the type of the projection.
    auto projectionType = ProjectTypeParser::parse(spec);
    // kComputed is a projection type reserved for $addFields, and should never be detected by the
    // ProjectTypeParser.
    invariant(projectionType != TransformerType::kComputedProjection);

    // We can't use make_unique() here, since the branches have different types.
    std::unique_ptr<ParsedAggregationProjection> parsedProject(
        projectionType == TransformerType::kInclusionProjection
            ? static_cast<ParsedAggregationProjection*>(new ParsedInclusionProjection(expCtx))
            : static_cast<ParsedAggregationProjection*>(new ParsedExclusionProjection(expCtx)));

    // Actually parse the specification.
    parsedProject->parse(spec);
    return parsedProject;
}