Files
mongo/jstests/aggregation/sources/densify/decimal.js
Zac 591928c619 SERVER-108478 JS formatted by prettier and remove clang-format (#39656)
GitOrigin-RevId: 6c8f6aded47f260aa4f7c231b17dae3302cb1e04
2025-08-21 17:27:09 +00:00

136 lines
4.6 KiB
JavaScript

/**
* Test that $densify works with Decimal128 type values.
* @tags: [
* # Needed as $densify is a 51 feature.
* requires_fcv_51,
* ]
*/
import {arrayEq} from "jstests/aggregation/extras/utils.js";
function buildErrorString(found, expected) {
return "Expected:\n" + tojson(expected) + "\nGot:\n" + tojson(found);
}
const coll = db[jsTestName()];
coll.drop();
assert.commandWorked(coll.insert([{val: NumberDecimal(0)}, {val: NumberDecimal(10)}]));
let pipeline = [{$project: {_id: 0}}, {$densify: {field: "val", range: {step: 1, bounds: "full"}}}];
let expectedResult = [];
for (let i = 0; i <= 10; i++) {
expectedResult.push({val: NumberDecimal(i)});
}
let result = coll.aggregate(pipeline).toArray();
assert(arrayEq(result, expectedResult), buildErrorString(result, expectedResult));
// Add a double in the middle of the range.
assert.commandWorked(coll.insert({val: 5}));
expectedResult = [];
// $densify uses the last type seen for generated documents.
for (let i = 0; i <= 10; i++) {
if (i < 5 || i == 10) {
expectedResult.push({val: NumberDecimal(i)});
} else {
expectedResult.push({val: i});
}
}
result = coll.aggregate(pipeline).toArray();
assert(arrayEq(result, expectedResult), buildErrorString(result, expectedResult));
// Run the same test, but with a Decimal step.
pipeline = [{$project: {_id: 0}}, {$densify: {field: "val", range: {step: NumberDecimal(1), bounds: "full"}}}];
expectedResult = [];
for (let i = 0; i <= 10; i++) {
if (i != 5) {
expectedResult.push({val: NumberDecimal(i)});
} else {
expectedResult.push({val: i});
}
}
result = coll.aggregate(pipeline).toArray();
assert(arrayEq(result, expectedResult), buildErrorString(result, expectedResult));
// Run the same test, but with decimals instead of integers.
coll.drop();
assert.commandWorked(coll.insert([{val: NumberDecimal(0)}, {val: 0.5}, {val: NumberDecimal(1)}]));
pipeline = [{$project: {_id: 0}}, {$densify: {field: "val", range: {step: 0.1, bounds: "full"}}}];
// Note that all the results after .5 may not be precisely on the step, but instead be off by a
// vanishingly small amount.
expectedResult = [
{val: NumberDecimal(0)},
{val: NumberDecimal(".1")},
{val: NumberDecimal(".2")},
{val: NumberDecimal(".3")},
{val: NumberDecimal(".4")},
{val: 0.5},
{val: 0.6},
{val: 0.7},
{val: 0.7999999999999999},
{val: 0.8999999999999999},
{val: 0.9999999999999999},
{val: NumberDecimal(1)},
];
result = coll.aggregate(pipeline).toArray();
assert(arrayEq(result, expectedResult), buildErrorString(result, expectedResult));
// Repeat with a NumberDecimal step
pipeline = [{$project: {_id: 0}}, {$densify: {field: "val", range: {step: NumberDecimal(".1"), bounds: "full"}}}];
expectedResult = [
{val: NumberDecimal(0)},
{val: NumberDecimal(".1")},
{val: NumberDecimal(".2")},
{val: NumberDecimal(".3")},
{val: NumberDecimal(".4")},
{val: 0.5},
{val: NumberDecimal(".6")},
{val: NumberDecimal(".7")},
{val: NumberDecimal(".8")},
{val: NumberDecimal(".9")},
{val: NumberDecimal(1)},
];
result = coll.aggregate(pipeline).toArray();
assert(arrayEq(result, expectedResult), buildErrorString(result, expectedResult));
// If the step is Decimal128, return Decimal128.
coll.drop();
assert.commandWorked(coll.insert([{val: 0}, {val: 1}]));
pipeline = [
{$project: {_id: 0}},
{$densify: {field: "val", range: {step: NumberDecimal(0.001), bounds: "full"}}},
// No need to check every value.
{$limit: 2},
];
result = coll.aggregate(pipeline).toArray();
assert(arrayEq(result, [{val: 0}, {val: NumberDecimal(0.001)}]));
// Decimal bounds fail if step is not decimal.
pipeline = [
{$project: {_id: 0}},
{$densify: {field: "val", range: {step: 0.1, bounds: [NumberDecimal(0.1), NumberDecimal(0.9)]}}},
// No need to check every value.
{$limit: 3},
];
assert.commandFailedWithCode(db.runCommand({aggregate: coll.getName(), pipeline: pipeline, cursor: {}}), 5876900);
// Verify that if 'step' is not representable as a double, precision is not lost during computation.
const preciseStep = NumberDecimal(".1243568735894448377382");
const preciseStepTimesTwo = NumberDecimal(".2487137471788896754764");
const preciseStepTimesThree = NumberDecimal(".3730706207683345132146");
pipeline = [
{$project: {_id: 0}},
{$densify: {field: "val", range: {step: preciseStep, bounds: "full"}}},
// No need to check every value.
{$limit: 4},
];
result = coll.aggregate(pipeline).toArray();
expectedResult = [{val: 0}, {val: preciseStep}, {val: preciseStepTimesTwo}, {val: preciseStepTimesThree}];
assert(arrayEq(result, expectedResult), buildErrorString(result, expectedResult));