Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(update): set CastError path to full path if casting update fails #14161

Merged
merged 7 commits into from Dec 24, 2023
9 changes: 8 additions & 1 deletion lib/schema/bigint.js
Expand Up @@ -212,7 +212,14 @@ SchemaBigInt.prototype.castForQuery = function($conditional, val, context) {
return this.applySetters(null, val, context);
}

return this.applySetters(val, context);
try {
return this.applySetters(val, context);
} catch (err) {
if (err instanceof CastError && err.path === this.path && this.$fullPath != null) {
err.path = this.$fullPath;
}
throw err;
}
};

/**
Expand Down
9 changes: 8 additions & 1 deletion lib/schema/boolean.js
Expand Up @@ -256,7 +256,14 @@ SchemaBoolean.prototype.castForQuery = function($conditional, val, context) {
return this.applySetters(null, val, context);
}

return this.applySetters(val, context);
try {
return this.applySetters(val, context);
} catch (err) {
if (err instanceof CastError && err.path === this.path && this.$fullPath != null) {
err.path = this.$fullPath;
}
throw err;
}
};

/**
Expand Down
11 changes: 10 additions & 1 deletion lib/schema/buffer.js
Expand Up @@ -279,7 +279,16 @@ SchemaBuffer.prototype.castForQuery = function($conditional, val, context) {
}
return handler.call(this, val);
}
const casted = this.applySetters(val, context);

let casted;
try {
casted = this.applySetters(val, context);
} catch (err) {
if (err instanceof CastError && err.path === this.path && this.$fullPath != null) {
err.path = this.$fullPath;
}
throw err;
}
return casted ? casted.toObject({ transform: false, virtuals: false }) : casted;
};

Expand Down
9 changes: 8 additions & 1 deletion lib/schema/date.js
Expand Up @@ -407,7 +407,14 @@ SchemaDate.prototype.$conditionalHandlers = {

SchemaDate.prototype.castForQuery = function($conditional, val, context) {
if ($conditional == null) {
return this.applySetters(val, context);
try {
return this.applySetters(val, context);
} catch (err) {
if (err instanceof CastError && err.path === this.path && this.$fullPath != null) {
err.path = this.$fullPath;
}
throw err;
}
}

const handler = this.$conditionalHandlers[$conditional];
Expand Down
11 changes: 10 additions & 1 deletion lib/schema/number.js
Expand Up @@ -429,7 +429,16 @@ SchemaNumber.prototype.castForQuery = function($conditional, val, context) {
}
return handler.call(this, val, context);
}
val = this.applySetters(val, context);

try {
val = this.applySetters(val, context);
} catch (err) {
if (err instanceof CastError && err.path === this.path && this.$fullPath != null) {
err.path = this.$fullPath;
}
throw err;
}

return val;
};

Expand Down
9 changes: 8 additions & 1 deletion lib/schema/string.js
Expand Up @@ -688,7 +688,14 @@ SchemaString.prototype.castForQuery = function($conditional, val, context) {
return val;
}

return this.applySetters(val, context);
try {
return this.applySetters(val, context);
} catch (err) {
if (err instanceof CastError && err.path === this.path && this.$fullPath != null) {
err.path = this.$fullPath;
}
throw err;
}
};

/*!
Expand Down
11 changes: 9 additions & 2 deletions lib/schema/uuid.js
Expand Up @@ -344,8 +344,15 @@ SchemaUUID.prototype.castForQuery = function($conditional, val, context) {
if (!handler)
throw new Error('Can\'t use ' + $conditional + ' with UUID.');
return handler.call(this, val, context);
} else {
return this.cast(val);
}

try {
return this.applySetters(val, context);
} catch (err) {
if (err instanceof CastError && err.path === this.path && this.$fullPath != null) {
err.path = this.$fullPath;
}
throw err;
}
};

Expand Down
9 changes: 8 additions & 1 deletion lib/schemaType.js
Expand Up @@ -1630,7 +1630,14 @@ SchemaType.prototype.castForQuery = function($conditional, val, context) {
return handler.call(this, val, context);
}

return this.applySetters(val, context);
try {
return this.applySetters(val, context);
} catch (err) {
if (err instanceof CastError && err.path === this.path && this.$fullPath != null) {
err.path = this.$fullPath;
}
throw err;
}
};

/**
Expand Down
30 changes: 30 additions & 0 deletions test/model.findOneAndUpdate.test.js
Expand Up @@ -2200,4 +2200,34 @@ describe('model: findOneAndUpdate:', function() {
);
assert.equal(updated.defaultField, 'some non-default value');
});

it('sets CastError path to full path (gh-14114)', async function() {
const testSchema = new mongoose.Schema({
id: mongoose.Schema.Types.ObjectId,
name: String,
accessories: [
{
isEnabled: Boolean,
additionals: [
{
k: String,
v: Number
}
]
}
]
});
const Test = db.model('Test', testSchema);
const err = await Test.findOneAndUpdate(
{},
{
$set: {
'accessories.0.additionals.0.k': ['test']
}
}
).then(() => null, err => err);
assert.ok(err);
assert.equal(err.name, 'CastError');
assert.equal(err.path, 'accessories.0.additionals.0.k');
});
});