Skip to content

Commit

Permalink
fix(update): handle embedded discriminators when casting array filters
Browse files Browse the repository at this point in the history
Fix #12565
  • Loading branch information
vkarpov15 committed Dec 15, 2022
1 parent 60b7f1c commit dba965e
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 15 deletions.
56 changes: 41 additions & 15 deletions lib/helpers/update/castArrayFilters.js
Expand Up @@ -37,36 +37,62 @@ function _castArrayFilters(arrayFilters, schema, strictQuery, updatedPathsByFilt
if (filter == null) {
throw new Error(`Got null array filter in ${arrayFilters}`);
}
for (const key of Object.keys(filter)) {
if (key === '$and' || key === '$or') {
const keys = Object.keys(filter).filter(key => filter[key] != null);
if (keys.length === 0) {
continue;
}

const firstKey = keys[0];
if (firstKey === '$and' || firstKey === '$or') {
for (const key of keys) {
_castArrayFilters(filter[key], schema, strictQuery, updatedPathsByFilter, query);
continue;
}
if (filter[key] == null) {
continue;
}
continue;
}
const dot = firstKey.indexOf('.');
const filterWildcardPath = dot === -1 ? firstKey : firstKey.substring(0, dot);
if (updatedPathsByFilter[filterWildcardPath] == null) {
continue;
}
const baseFilterPath = cleanPositionalOperators(
updatedPathsByFilter[filterWildcardPath]
);

const baseSchematype = getPath(schema, baseFilterPath);
let filterBaseSchema = baseSchematype != null ? baseSchematype.schema : null;
if (filterBaseSchema != null &&
filterBaseSchema.discriminators != null &&
filter[filterWildcardPath + '.' + filterBaseSchema.options.discriminatorKey]) {
filterBaseSchema = filterBaseSchema.discriminators[filter[filterWildcardPath + '.' + filterBaseSchema.options.discriminatorKey]] || filterBaseSchema;
}

for (const key of keys) {
if (updatedPathsByFilter[key] === null) {
continue;
}
if (Object.keys(updatedPathsByFilter).length === 0) {
continue;
}
const dot = key.indexOf('.');
let filterPath = dot === -1 ?
updatedPathsByFilter[key] + '.0' :
updatedPathsByFilter[key.substring(0, dot)] + '.0' + key.substring(dot);
if (filterPath == null) {
throw new Error(`Filter path not found for ${key}`);

let filterPathRelativeToBase = dot === -1 ? null : key.substring(dot);
let schematype;
if (filterPathRelativeToBase == null || filterBaseSchema == null) {
schematype = baseSchematype;
} else {
// If there are multiple array filters in the path being updated, make sure
// to replace them so we can get the schema path.
filterPathRelativeToBase = cleanPositionalOperators(filterPathRelativeToBase);
schematype = getPath(filterBaseSchema, filterPathRelativeToBase);
}

// If there are multiple array filters in the path being updated, make sure
// to replace them so we can get the schema path.
filterPath = cleanPositionalOperators(filterPath);
const schematype = getPath(schema, filterPath);
if (schematype == null) {
if (!strictQuery) {
return;
}
const filterPath = filterPathRelativeToBase == null ?
baseFilterPath + '.0' :
baseFilterPath + '.0' + filterPathRelativeToBase;
// For now, treat `strictQuery = true` and `strictQuery = 'throw'` as
// equivalent for casting array filters. `strictQuery = true` doesn't
// quite work in this context because we never want to silently strip out
Expand Down
49 changes: 49 additions & 0 deletions test/helpers/update.castArrayFilters.test.js
Expand Up @@ -262,4 +262,53 @@ describe('castArrayFilters', function() {
castArrayFilters(q);
}, /Could not find path "arr\.0\.notInSchema" in schema/);
});

it('handles embedded discriminators (gh-12565)', function() {
const elementSchema = new Schema(
{ elementType: String },
{ discriminatorKey: 'elementType' }
);
const versionSchema = new Schema(
{ version: Number, elements: [elementSchema] },
{ strictQuery: 'throw' }
);
versionSchema.path('elements').discriminator(
'Graph',
new Schema({
number: Number,
curves: [{ line: { label: String, type: String, number: String, latLong: [Number], controller: String } }]
})
);

const testSchema = new Schema({ versions: [versionSchema] });

const q = new Query();
q.schema = testSchema;

const p = {
$push: {
'versions.$[version].elements.$[element].curves': {
line: {
label: 'CC110_Ligne 02',
type: 'numerique',
number: '30',
latLong: [44, 8],
controller: 'CC110'
}
}
}
};
const opts = {
arrayFilters: [
{
'element.elementType': 'Graph',
'element.number': '1'
}
]
};
q.updateOne({}, p, opts);
castArrayFilters(q);

assert.strictEqual(q.options.arrayFilters[0]['element.number'], 1);
});
});

0 comments on commit dba965e

Please sign in to comment.