Skip to content

Commit

Permalink
Use attribute getter for sort filter
Browse files Browse the repository at this point in the history
  • Loading branch information
ogonkov authored and fdintino committed Jul 30, 2020
1 parent c7337e7 commit 0c02062
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 4 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
Changelog
=========

Unreleased
----------

* Add support for nested attributes on
[`sort` filter](https://mozilla.github.io/nunjucks/templating.html#sort-arr-reverse-casesens-attr);
respect `throwOnUndefined` if sort attribute is undefined.

3.2.2 (Jul 20 2020)
-------------------

Expand Down
14 changes: 11 additions & 3 deletions nunjucks/src/filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -447,13 +447,21 @@ exports.sum = sum;

exports.sort = r.makeMacro(
['value', 'reverse', 'case_sensitive', 'attribute'], [],
(arr, reversed, caseSens, attr) => {
function sortFilter(arr, reversed, caseSens, attr) {
// Copy it
let array = lib.map(arr, v => v);
let getAttribute = lib.getAttrGetter(attr);

array.sort((a, b) => {
let x = (attr) ? a[attr] : a;
let y = (attr) ? b[attr] : b;
let x = (attr) ? getAttribute(a) : a;
let y = (attr) ? getAttribute(b) : b;

if (
this.env.opts.throwOnUndefined &&
attr && (x === undefined || y === undefined)
) {
throw new TypeError(`sort: attribute "${attr}" resolved to undefined`);
}

if (!caseSens && lib.isString(x) && lib.isString(y)) {
x = x.toLowerCase();
Expand Down
2 changes: 2 additions & 0 deletions nunjucks/src/lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ function getAttrGetter(attribute) {
};
}

exports.getAttrGetter = getAttrGetter;

function groupBy(obj, val, throwOnUndefined) {
const result = {};
const iterator = isFunction(val) ? val : getAttrGetter(val);
Expand Down
2 changes: 1 addition & 1 deletion nunjucks/src/runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class Frame {
}

function makeMacro(argNames, kwargNames, func) {
return (...macroArgs) => {
return function macro(...macroArgs) {
var argCount = numArgs(macroArgs);
var args;
var kwargs = getKeywordArgs(macroArgs);
Expand Down
29 changes: 29 additions & 0 deletions tests/filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,35 @@
equal('{% for i in [ {n:3},{n:5},{n:2},{n:1},{n:4},{n:6}] | sort(attribute="n") %}{{ i.n }}{% endfor %}',
'123456');

const nestedAttributeSortTemplate = '{% for item in items | sort(attribute="meta.age") %}{{ item.name }}{% endfor %}';
equal(
nestedAttributeSortTemplate,
{
items: [
{name: 'james', meta: {age: 25}},
{name: 'fred', meta: {age: 18}},
{name: 'john', meta: {age: 19}}
]
},
'fredjohnjames'
);

expect(function() {
render(
nestedAttributeSortTemplate,
{
items: [
{name: 'james', meta: {age: 25}},
{name: 'fred', meta: {age: 18}},
{name: 'john', meta: {title: 'Developer'}}
]
},
{
throwOnUndefined: true
}
);
}).to.throwError(/sort: attribute "meta\.age" resolved to undefined/);

finish(done);
});

Expand Down

0 comments on commit 0c02062

Please sign in to comment.