Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7406 from Automattic/gh7079
WIP: casting arrayFilters
- Loading branch information
Showing
6 changed files
with
225 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -337,4 +337,4 @@ function _cast(val, numbertype, context) { | |
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
'use strict'; | ||
|
||
module.exports = function castFilterPath(query, schematype, val) { | ||
const any$conditionals = Object.keys(val).some(function(k) { | ||
return k.charAt(0) === '$' && k !== '$id' && k !== '$ref'; | ||
}); | ||
|
||
if (!any$conditionals) { | ||
return schematype.castForQueryWrapper({ | ||
val: val, | ||
context: query | ||
}); | ||
} | ||
|
||
const ks = Object.keys(val); | ||
|
||
let k = ks.length; | ||
|
||
while (k--) { | ||
const $cond = ks[k]; | ||
const nested = val[$cond]; | ||
|
||
if ($cond === '$not') { | ||
if (nested && schematype && !schematype.caster) { | ||
const _keys = Object.keys(nested); | ||
if (_keys.length && _keys[0].charAt(0) === '$') { | ||
for (const key in nested) { | ||
nested[key] = schematype.castForQueryWrapper({ | ||
$conditional: key, | ||
val: nested[key], | ||
context: context | ||
}); | ||
} | ||
} else { | ||
val[$cond] = schematype.castForQueryWrapper({ | ||
$conditional: $cond, | ||
val: nested, | ||
context: context | ||
}); | ||
} | ||
continue; | ||
} | ||
// cast(schematype.caster ? schematype.caster.schema : schema, nested, options, context); | ||
} else { | ||
val[$cond] = schematype.castForQueryWrapper({ | ||
$conditional: $cond, | ||
val: nested, | ||
context: context | ||
}); | ||
} | ||
} | ||
|
||
return val; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
'use strict'; | ||
|
||
const castFilterPath = require('../query/castFilterPath'); | ||
const modifiedPaths = require('./modifiedPaths'); | ||
|
||
module.exports = function castArrayFilters(query) { | ||
const arrayFilters = query.options.arrayFilters; | ||
if (!Array.isArray(arrayFilters)) { | ||
return; | ||
} | ||
|
||
const update = query.getUpdate(); | ||
const schema = query.schema; | ||
|
||
const updatedPaths = modifiedPaths(update); | ||
|
||
const updatedPathsByFilter = Object.keys(updatedPaths).reduce((cur, path) => { | ||
const matches = path.match(/\$\[[^\]]+\]/g); | ||
if (matches == null) { | ||
return cur; | ||
} | ||
for (const match of matches) { | ||
const firstMatch = path.indexOf(match); | ||
if (firstMatch !== path.lastIndexOf(match)) { | ||
throw new Error(`Path '${path}' contains the same array filter multiple times`); | ||
} | ||
cur[match.substring(2, match.length - 1)] = path.substr(0, firstMatch - 1); | ||
} | ||
return cur; | ||
}, {}); | ||
|
||
for (const filter of arrayFilters) { | ||
if (filter == null) { | ||
throw new Error(`Got null array filter in ${arrayFilters}`); | ||
} | ||
const firstKey = Object.keys(filter)[0]; | ||
|
||
if (filter[firstKey] == null) { | ||
continue; | ||
} | ||
|
||
const dot = firstKey.indexOf('.'); | ||
let filterPath = dot === -1 ? | ||
updatedPathsByFilter[firstKey] + '.0' : | ||
updatedPathsByFilter[firstKey.substr(0, dot)] + '.0' + firstKey.substr(dot); | ||
|
||
if (filterPath == null) { | ||
throw new Error(`Filter path not found for ${firstKey}`); | ||
} | ||
|
||
// If there are multiple array filters in the path being updated, make sure | ||
// to replace them so we can get the schema path. | ||
filterPath = filterPath.replace(/\$\[[^\]]+\]/g, '0'); | ||
|
||
const schematype = schema.path(filterPath); | ||
if (typeof filter[firstKey] === 'object') { | ||
filter[firstKey] = castFilterPath(query, schematype, filter[firstKey]); | ||
} else { | ||
filter[firstKey] = schematype.castForQuery(filter[firstKey]); | ||
} | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
'use strict'; | ||
|
||
const Query = require('../../lib/query'); | ||
const Schema = require('../../lib/schema'); | ||
const assert = require('assert'); | ||
const castArrayFilters = require('../../lib/helpers/update/castArrayFilters'); | ||
|
||
describe('castArrayFilters', function() { | ||
it('works', function(done) { | ||
const schema = new Schema({ comments: [{ date: Date }] }); | ||
const q = new Query(); | ||
q.schema = schema; | ||
|
||
q.updateOne({}, { $set: { 'comments.$[x].date': '2018-01-01' } }, { | ||
arrayFilters: [{ 'x.date': { $gte: '2018-01-01' } }] | ||
}); | ||
castArrayFilters(q); | ||
|
||
assert.ok(q.options.arrayFilters[0]['x.date'].$gte instanceof Date); | ||
|
||
done(); | ||
}); | ||
|
||
it('casts multiple', function(done) { | ||
const schema = new Schema({ | ||
comments: [{ | ||
text: String, | ||
replies: [{ date: Date }] | ||
}] | ||
}); | ||
const q = new Query(); | ||
q.schema = schema; | ||
|
||
q.updateOne({}, { $set: { 'comments.$[x].replies.$[y].date': '2018-01-01' } }, { | ||
arrayFilters: [{ 'x.text': 123 }, { 'y.date': { $gte: '2018-01-01' } }] | ||
}); | ||
castArrayFilters(q); | ||
|
||
assert.strictEqual(q.options.arrayFilters[0]['x.text'], '123'); | ||
assert.ok(q.options.arrayFilters[1]['y.date'].$gte instanceof Date); | ||
|
||
done(); | ||
}); | ||
|
||
it('sane error on same filter twice', function(done) { | ||
const schema = new Schema({ | ||
comments: [{ | ||
text: String, | ||
replies: [{ date: Date }] | ||
}] | ||
}); | ||
const q = new Query(); | ||
q.schema = schema; | ||
|
||
q.updateOne({}, { $set: { 'comments.$[x].replies.$[x].date': '2018-01-01' } }, { | ||
arrayFilters: [{ 'x.text': 123 }] | ||
}); | ||
|
||
assert.throws(() => { | ||
castArrayFilters(q); | ||
}, /same array filter/); | ||
|
||
done(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters