8000 Implement 'dictsort' filter · jinja2cpp/Jinja2Cpp@cc31dad · GitHub
[go: up one dir, main page]

Skip to content

Commit cc31dad

Browse files
committed
Implement 'dictsort' filter
1 parent 7a4b508 commit cc31dad

File tree

5 files changed

+90
-7
lines changed

5 files changed

+90
-7
lines changed

src/expression_parser.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,8 @@ ExpressionEvaluatorPtr<ExpressionFilter> ExpressionParser::ParseFilterExpression
522522

523523
if (lexer.NextToken() == '(')
524524
params = ParseCallParams(lexer, valid);
525+
else
526+
lexer.ReturnToken();
525527

526528
if (!valid)
527529
return empty;

src/filters.cpp

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,12 +195,75 @@ InternalValue Default::Filter(const InternalValue& baseVal, RenderContext& conte
195195

196196
DictSort::DictSort(FilterParams params)
197197
{
198-
198+
ParseParams({{"case_sensitive", false}, {"by", false, std::string("key")}, {"reverse", false}}, params);
199199
}
200200

201201
InternalValue DictSort::Filter(const InternalValue& baseVal, RenderContext& context)
202202
{
203-
return InternalValue();
203+
const MapAdapter* map = boost::get<MapAdapter>(&baseVal);
204+
if (map == nullptr)
205+
return InternalValue();
206+
207+
InternalValue isReverseVal = GetArgumentValue("reverse", context, InternalValue(false));
208+
InternalValue isCsVal = GetArgumentValue("case_sensitive", context, InternalValue(false));
209+
InternalValue byVal = GetArgumentValue("by", context, InternalValue(std::string("key")));
210+
211+
bool (*comparator)(const KeyValuePair& left, const KeyValuePair& right);
212+
213+
if (AsString(byVal) == "key") // Sort by key
214+
{
215+
if (ConvertToBool(isCsVal))
216+
{
217+
comparator = [](const KeyValuePair& left, const KeyValuePair& right)
218+
{
219+
return left.key < right.key;
220+
};
221+
}
222+
else
223+
{
224+
comparator = [](const KeyValuePair& left, const KeyValuePair& right)
225+
{
226+
return boost::lexicographical_compare(left.key, right.key, boost::algorithm::is_iless());
227+
};
228+
}
229+
}
230+
else if (AsString(byVal) == "value")
231+
{
232+
if (ConvertToBool(isCsVal))
233+
{
234+
comparator = [](const KeyValuePair& left, const KeyValuePair& right)
235+
{
236+
return ConvertToBool(Apply2<visitors::BinaryMathOperation>(left.value, right.value, BinaryExpression::LogicalLt, BinaryExpression::CaseSensitive));
237+
};
238+
}
239+
else
240+
{
241+
comparator = [](const KeyValuePair& left, const KeyValuePair& right)
242+
{
243+
return ConvertToBool(Apply2<visitors::BinaryMathOperation>(left.value, right.value, BinaryExpression::LogicalLt, BinaryExpression::CaseInsensitive));
244+
};
245+
}
246+
}
247+
else
248+
return InternalValue();
249+
250+
std::vector<KeyValuePair> tempVector;
251+
tempVector.reserve(map->GetSize());
252+
for (int64_t idx = 0; idx < map->GetSize(); ++ idx)
253+
{
254+
auto val = map->GetValueByIndex(idx);
255+
auto& kvVal = boost::get<KeyValuePair>(val);
256+
tempVector.push_back(std::move(kvVal));
257+
}
258+
259+
if (ConvertToBool(isReverseVal))
260+
std::sort(tempVector.begin(), tempVector.end(), [comparator](auto& l, auto& r) {return comparator(r, l);});
261+
else
262+
std::sort(tempVector.begin(), tempVector.end(), [comparator](auto& l, auto& r) {return comparator(l, r);});
263+
264+
InternalValueList resultList(tempVector.begin(), tempVector.end());
265+
266+
return InternalValue(ListAdapter::CreateAdapter(std::move(resultList)));
204267
}
205268

206269
GroupBy::GroupBy(FilterParams params)
@@ -311,7 +374,7 @@ struct PrettyPrinter : visitors::BaseVisitor<InternalValue>
311374
std::ostringstream os;
312375

313376
os << "'" << kwPair.key << "': ";
314-
os << AsString(Apply<PrettyPrinter>(kwPair, m_context));
377+
os << AsString(Apply<PrettyPrinter>(kwPair.value, m_context));
315378

316379
return InternalValue(os.str());
317380
}

src/internal_value.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -283,14 +283,14 @@ class InternalValueMapAdapter : public IMapAccessor
283283
size_t GetSize() const override {return m_values.Get().size();}
284284
InternalValue GetValueByIndex(int64_t idx) const override
285285
{
286-
InternalValueMap result;
286+
KeyValuePair result;
287287
auto p = m_values.Get().begin();
288288
std::advance(p, idx);
289289

290-
result["key"] = InternalValue(p->first);
291-
result["value"] = p->second;
290+
result.key = p->first;
291+
result.value = p->second;
292292

293-
return MapAdapter::CreateAdapter(std::move(result));
293+
return InternalValue(std::move(result));
294294
}
295295
bool HasValue(const std::string& name) const override
296296
{

test/filters_test.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,3 +216,15 @@ INSTANTIATE_TEST_CASE_P(PPrint, FilterGenericTest, ::testing::Values(
216216
InputOutputPair{"{'key'='itemName'} | pprint", "{'key': 'itemName'}"}
217217
));
218218

219+
220+
INSTANTIATE_TEST_CASE_P(DictSort, FilterGenericTest, ::testing::Values(
221+
InputOutputPair{"{'key'='itemName', 'Value'='ItemValue'} | dictsort | pprint", "['key': 'itemName', 'Value': 'ItemValue']"},
222+
InputOutputPair{"{'key'='itemName', 'Value'='ItemValue'} | dictsort(by='value') | pprint", "['key': 'itemName', 'Value': 'ItemValue']"},
223+
InputOutputPair{"{'key'='itemName', 'Value'='ItemValue'} | dictsort(reverse=true) | pprint", "['Value': 'ItemValue', 'key': 'itemName']"},
224+
InputOutputPair{"{'key'='itemName', 'Value'='ItemValue'} | dictsort(reverse=true, by='value') | pprint", "['Value': 'ItemValue', 'key': 'itemName']"},
225+
InputOutputPair{"{'key'='itemName', 'Value'='ItemValue'} | dictsort(case_sensitive=true) | pprint", "['Value': 'ItemValue', 'key': 'itemName']"},
226+
InputOutputPair{"{'key'='itemName', 'Value'='ItemValue'} | dictsort(case_sensitive=true, reverse=true) | pprint", "['key': 'itemName', 'Value': 'ItemValue']"},
227+
InputOutputPair{"simpleMapValue | dictsort | pprint", "['boolValue': true, 'dblVal': 100.5, 'intVal': 10, 'stringVal': 'string100.5']"},
228+
InputOutputPair{"reflectedVal | dictsort | pprint", "['boolValue': false, 'dblValue': 0, 'intValue': 0, 'strValue': 'test string 0', 'wstrValue': '<wchar_string>']"}
229+
));
230+

test/test_tools.h

Lines changed: 6 additions & 0 deletions
4284
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ inline jinja2::ValuesMap PrepareTestData()
7373
{"boolValue", true},
7474
{"reflectedList", testData}
7575
}},
76+
{"simpleMapValue", jinja2::ValuesMap{
77+
{"intVal", 10},
78+
{"dblVal", 100.5},
79+
{"stringVal", "string100.5"},
80+
{"boolValue", true}
81+
}},
7682
{"reflectedVal", jinja2::Reflect(sampleStruct)},
7783
{"emptyReflectedPtrVal", jinja2::Reflect(emptyTestStruct)},
7884
{"filledReflectedPtrVal", jinja2::Reflect(filledTestStruct)},

0 commit comments

Comments
 (0)
0