Implement sort-by clause parser <field-name>, [DESC | ASC] e.g "name DESC" (default to ASC)

This commit is contained in:
Artem Pavlenko 2025-10-27 13:56:34 +00:00
parent d8acccb636
commit 5d9183fa97
6 changed files with 91 additions and 14 deletions

View File

@ -427,7 +427,7 @@ void feature_style_processor<Processor>::prepare_layer(layer_rendering_material&
auto sort_by = lay.sort_by();
if (sort_by)
{
q.add_property_name(*sort_by);
q.add_property_name((*sort_by).first);
}
bool cache_features = lay.cache_features() && active_styles.size() > 1;
@ -502,7 +502,7 @@ void feature_style_processor<Processor>::render_material(layer_rendering_materia
{
cache->push(feature);
}
cache->sort_by(*sort_by, true);
cache->sort_by((*sort_by).first, (*sort_by).second);
std::size_t i = 0;
for (feature_type_style const* style : active_styles)
{

View File

@ -27,10 +27,11 @@
#include <mapnik/well_known_srs.hpp>
#include <mapnik/geometry/box2d.hpp>
#include <mapnik/image_compositing.hpp>
#include <mapnik/util/sort_by.hpp>
// stl
#include <vector>
#include <memory>
#include <tuple>
namespace mapnik {
@ -194,12 +195,12 @@ class MAPNIK_DECL layer
/*!
* @param column Set the field rendering of this layer is sorted by.
*/
void set_sort_by(std::string const& column);
void set_sort_by(std::string const& column, bool desc = false);
/*!
* @return optional field rendering of this layer is sorted by.
* @return optional field (+order) rendering of this layer is sorted by.
*/
std::optional<std::string> const& sort_by() const;
std::optional<sort_by_type> const& sort_by() const;
/*!
* @brief Attach a datasource for this layer.
@ -242,7 +243,7 @@ class MAPNIK_DECL layer
bool clear_label_cache_;
bool cache_features_;
std::string group_by_;
std::optional<std::string> sort_by_;
std::optional<sort_by_type> sort_by_;
std::vector<std::string> styles_;
std::vector<layer> layers_;
datasource_ptr ds_;

View File

@ -0,0 +1,58 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2025 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#ifndef MAPNIK_SORT_BY_HPP
#define MAPNIK_SORT_BY_HPP
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/std_pair.hpp>
namespace mapnik {
using sort_by_type = std::pair<std::string, bool>;
inline bool parse_sort_by(std::string const& str, sort_by_type & result)
{
namespace x3 = boost::spirit::x3;
auto itr = str.begin();
auto end = str.end();
auto apply_sort_by = [&](auto const& ctx) {
result.first = _attr(ctx);
};
auto apply_desc = [&](auto const& ctx) {
result.second = true;
};
if (!x3::phrase_parse(itr, end,
x3::no_skip[(+x3::char_("a-zA-Z_0-9-"))][apply_sort_by]
> -(x3::no_case[x3::lit("DESC")][apply_desc] | x3::no_case[x3::lit("ASC")]),
// ASC is a default
x3::space
) || (itr != end))
{
return false;
}
return true;
}
} // namespace mapnik
#endif // MAPNIK_SORT_BY_HPP

View File

@ -297,12 +297,12 @@ std::string const& layer::group_by() const
return group_by_;
}
void layer::set_sort_by(std::string const& column)
void layer::set_sort_by(std::string const& column, bool desc)
{
sort_by_ = column;
sort_by_ = {column, desc};
}
std::optional<std::string> const& layer::sort_by() const
std::optional<sort_by_type> const& layer::sort_by() const
{
return sort_by_;
}

View File

@ -49,6 +49,7 @@
#include <mapnik/util/dasharray_parser.hpp>
#include <mapnik/util/conversions.hpp>
#include <mapnik/util/trim.hpp>
#include <mapnik/util/sort_by.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/util/noncopyable.hpp>
#include <mapnik/util/fs.hpp>
@ -751,10 +752,23 @@ void map_parser::parse_layer(Parent& parent, xml_node const& node)
lyr.set_group_by(*group_by);
}
optional<std::string> sort_by = node.get_opt_attr<std::string>("sort-by");
if (sort_by)
optional<std::string> str = node.get_opt_attr<std::string>("sort-by");
if (str)
{
lyr.set_sort_by(*sort_by);
mapnik::sort_by_type result;
if (!mapnik::parse_sort_by(*str, result))
{
std::string s_err("failed to parse Layer sort-by clause \"" + *str + "\"");
if (strict_)
{
throw config_error(s_err);
}
else
{
MAPNIK_LOG_ERROR(load_map) << "map_parser: " << s_err;
}
}
lyr.set_sort_by(result.first, result.second);
}
optional<int> buffer_size = node.get_opt_attr<int>("buffer-size");

View File

@ -549,7 +549,11 @@ void serialize_layer(ptree& map_node, layer const& lyr, bool explicit_defaults)
if (lyr.sort_by() || explicit_defaults)
{
set_attr(layer_node, "sort-by", *lyr.sort_by());
auto sort_by = *lyr.sort_by();
std::string str = sort_by.first;
if (sort_by.second)
str += " DESC";
set_attr(layer_node, "sort-by", str);
}
auto&& buffer_size = lyr.buffer_size();