// Copyright Contributors to the DNF5 project.
// Copyright Contributors to the libdnf project.
// SPDX-License-Identifier: LGPL-2.1-or-later
//
// This file is part of libdnf: https://github.com/rpm-software-management/libdnf/
//
// Libdnf 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.
//
// Libdnf 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 libdnf.  If not, see <https://www.gnu.org/licenses/>.

#ifndef LIBDNF5_RPM_PACKAGE_QUERY_HPP
#define LIBDNF5_RPM_PACKAGE_QUERY_HPP


#include "nevra.hpp"
#include "package_sack.hpp"
#include "package_set.hpp"

#include "libdnf5/base/base_weak.hpp"
#include "libdnf5/base/goal_elements.hpp"
#include "libdnf5/common/exception.hpp"
#include "libdnf5/common/sack/exclude_flags.hpp"
#include "libdnf5/common/sack/query_cmp.hpp"
#include "libdnf5/defs.h"

#include <string>
#include <vector>


namespace libdnf5 {

class Goal;

}  // namespace libdnf5


namespace libdnf5::rpm {

// @replaces libdnf/hy-query.h:struct:HyQuery
// @replaces libdnf/sack/query.hpp:struct:Query
// @replaces hawkey:hawkey/__init__.py:class:Query
class LIBDNF_API PackageQuery : public PackageSet {
public:
    using ExcludeFlags = libdnf5::sack::ExcludeFlags;

    // @replaces libdnf/hy-query.h:function:hy_query_create(DnfSack *sack);
    // @replaces libdnf/hy-query.h:function:hy_query_create_flags(DnfSack *sack, int flags);
    // @replaces libdnf/sack/query.hpp:method:Query(DnfSack* sack, ExcludeFlags flags = ExcludeFlags::APPLY_EXCLUDES)
    // @replaces libdnf/dnf-reldep.h:function:dnf_reldep_free(DnfReldep *reldep)
    explicit PackageQuery(
        const libdnf5::BaseWeakPtr & base, ExcludeFlags flags = ExcludeFlags::APPLY_EXCLUDES, bool empty = false);
    explicit PackageQuery(libdnf5::Base & base, ExcludeFlags flags = ExcludeFlags::APPLY_EXCLUDES, bool empty = false);

    /// Construct a new PackageQuery based on given PackageSet. This is a shortcut to creating
    /// an empty PackageQuery and then updating it with the content of pkgset.
    /// @param pkgset  A packageset that the new query will contain
    /// @param flags   Which excludes the query respects
    explicit PackageQuery(const PackageSet & pkgset, ExcludeFlags flags = ExcludeFlags::APPLY_EXCLUDES);

    PackageQuery(const PackageQuery & src);
    PackageQuery(PackageQuery && src) noexcept;
    ~PackageQuery();

    PackageQuery & operator=(const PackageQuery & src);
    PackageQuery & operator=(PackageQuery && src) noexcept;

    /// Filter packages by their `name`.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`, `IEXACT`, `NOT_IEXACT`, `ICONTAINS`, `NOT_ICONTAINS`, `IGLOB`, `NOT_IGLOB`, `CONTAINS`, `NOT_CONTAINS`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_NAME
    void filter_name(const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_name(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by their `name`.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`, `IEXACT`, `NOT_IEXACT`, `ICONTAINS`, `NOT_ICONTAINS`, `IGLOB`, `NOT_IGLOB`, `CONTAINS`, `NOT_CONTAINS`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char **matches) - cmp_type = HY_PKG_NAME
    void filter_name(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `name` based on names of the packages in the `package_set`.
    ///
    /// @param package_set      PackageSet with Package objects the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`.
    /// @since 5.0
    void filter_name(const PackageSet & package_set, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `epoch`.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.2
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_EPOCH
    void filter_epoch(const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_epoch(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by their `epoch`.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char **matches) - cmp_type = HY_PKG_EPOCH
    void filter_epoch(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `epoch`.
    ///
    /// @param pattern          A number the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GT`, `GTE`, `LT`, `LTE`.
    /// @since 5.2
    void filter_epoch(unsigned long pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_epoch(std::vector<unsigned long>{pattern}, cmp_type);
    };

    /// Filter packages by their `epoch`.
    ///
    /// @param patterns         A vector of numbers the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GT`, `GTE`, `LT`, `LTE`.
    /// @since 5.0
    void filter_epoch(
        const std::vector<unsigned long> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `version`.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GT`, `GTE`, `LT`, `LTE`, `GLOB`, `NOT_GLOB`.
    /// @since 5.2
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_VERSION
    void filter_version(const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_version(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by their `version`.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GT`, `GTE`, `LT`, `LTE`, `GLOB`, `NOT_GLOB`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char **matches) - cmp_type = HY_PKG_VERSION
    void filter_version(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `release`.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GT`, `GTE`, `LT`, `LTE`, `GLOB`, `NOT_GLOB`.
    /// @since 5.2
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_RELEASE
    void filter_release(const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_release(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by their `release`.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GT`, `GTE`, `LT`, `LTE`, `GLOB`, `NOT_GLOB`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_RELEASE
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char **matches) - cmp_type = HY_PKG_RELEASE
    void filter_release(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `arch`.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.2
    void filter_arch(const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_arch(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by their `arch`.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.0
    void filter_arch(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `vendor`.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`, `IEXACT`, `NOT_IEXACT`, `ICONTAINS`, `NOT_ICONTAINS`, `IGLOB`, `NOT_IGLOB`, `CONTAINS`, `NOT_CONTAINS`.
    /// @since 5.3
    void filter_vendor(const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_vendor(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by their `vendor`.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`, `IEXACT`, `NOT_IEXACT`, `ICONTAINS`, `NOT_ICONTAINS`, `IGLOB`, `NOT_IGLOB`, `CONTAINS`, `NOT_CONTAINS`.
    /// @since 5.3
    void filter_vendor(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `name` and `arch` based on names and arches of the packages in the `package_set`.
    ///
    /// @param package_set      PackageSet with Package objects the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`.
    /// @since 5.0
    void filter_name_arch(
        const PackageSet & package_set, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `epoch:version-release`.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `GT`, `LT`, `GTE`, `LTE`, `EQ`.
    /// @since 5.2
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_EVR
    void filter_evr(const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_evr(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by their `epoch:version-release`.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `GT`, `LT`, `GTE`, `LTE`, `NEQ`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char **matches) - cmp_type = HY_PKG_EVR
    void filter_evr(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `name-[epoch:]version-release.arch`. The following matches are tolerant to omitted 0 epoch: `EQ`, `NEQ`, `GT`, `GTE`, `LT`, `LTE`.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GT`, `GTE`, `LT`, `LTE`, `GLOB`, `NOT_GLOB`, `IGLOB`, `NOT_IGLOB`, `IEXACT`, `NOT_IEXACT`.
    /// @since 5.2
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_NEVRA
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_NEVRA_STRICT
    void filter_nevra(const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_nevra(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by their `name-[epoch:]version-release.arch`. The following matches are tolerant to omitted 0 epoch: `EQ`, `NEQ`, `GT`, `GTE`, `LT`, `LTE`.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GT`, `GTE`, `LT`, `LTE`, `GLOB`, `NOT_GLOB`, `IGLOB`, `NOT_IGLOB`, `IEXACT`, `NOT_IEXACT`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char **matches) - cmp_type = HY_PKG_NEVRA
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char **matches) - cmp_type = HY_PKG_NEVRA_STRICT
    void filter_nevra(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by the `name`, `epoch`, `version`, `release` and `arch` attributes from the `nevra` object.
    /// Only the attributes that are not blank are used in the filter.
    ///
    /// @param nevra            A Nevra object the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`, `IEXACT`, `NOT_IEXACT`, `IGLOB`, `NOT_IGLOB`.
    /// @since 5.0
    void filter_nevra(
        const libdnf5::rpm::Nevra & nevra, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `name-[epoch:]version-release.arch` attributes of
    /// the packages in the `package_set`.
    /// Only packages whose name.arch is present in the `package_set` are taken into
    /// account. Their epoch:version-release are then compared according to the
    /// value of `cmp_type` with those in `package_set`.
    /// Only the matching packages are kept in the query. In case `NOT` is used in
    /// `cmp_type`, the matching packages are removed from the query.
    ///
    /// @param package_set      PackageSet with Package objects the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GT`, `GTE`, `LT`, `LTE`,
    ///                         and their combinations with `NOT`.
    /// @since 5.0
    void filter_nevra(const PackageSet & package_set, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `sourcerpm`.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_SOURCERPM
    void filter_sourcerpm(const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_sourcerpm(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by their `sourcerpm`.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char **matches) - cmp_type = HY_PKG_SOURCERPM
    void filter_sourcerpm(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `url`.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`, `IEXACT`, `NOT_IEXACT`, `ICONTAINS`, `NOT_ICONTAINS`, `IGLOB`, `NOT_IGLOB`, `CONTAINS`, `NOT_CONTAINS`.
    /// @since 5.2
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_URL
    void filter_url(const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_url(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by their `url`.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`, `IEXACT`, `NOT_IEXACT`, `ICONTAINS`, `NOT_ICONTAINS`, `IGLOB`, `NOT_IGLOB`, `CONTAINS`, `NOT_CONTAINS`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char **matches) - cmp_type = HY_PKG_URL
    void filter_url(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `summary`.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`, `IEXACT`, `NOT_IEXACT`, `ICONTAINS`, `NOT_ICONTAINS`, `IGLOB`, `NOT_IGLOB`, `CONTAINS`, `NOT_CONTAINS`.
    /// @since 5.2
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_SUMMARY
    void filter_summary(const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_summary(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by their `summary`.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`, `IEXACT`, `NOT_IEXACT`, `ICONTAINS`, `NOT_ICONTAINS`, `IGLOB`, `NOT_IGLOB`, `CONTAINS`, `NOT_CONTAINS`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char **matches) - cmp_type = HY_PKG_SUMMARY
    void filter_summary(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `description`.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`, `IEXACT`, `NOT_IEXACT`, `ICONTAINS`, `NOT_ICONTAINS`, `IGLOB`, `NOT_IGLOB`, `CONTAINS`, `NOT_CONTAINS`.
    /// @since 5.2
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_DESCRIPTION
    void filter_description(
        const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_description(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by their `description`.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`, `IEXACT`, `NOT_IEXACT`, `ICONTAINS`, `NOT_ICONTAINS`, `IGLOB`, `NOT_IGLOB`, `CONTAINS`, `NOT_CONTAINS`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char **matches) - cmp_type = HY_PKG_DESCRIPTION
    void filter_description(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `provides`.
    ///
    /// @param reldep_list      ReldepList with RelDep objects the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const Dependency * reldep) - cmp_type = HY_PKG_PROVIDES
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const DependencyContainer * reldeplist) - cmp_type = HY_PKG_PROVIDES
    void filter_provides(
        const ReldepList & reldep_list, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `provides`.
    ///
    /// @param reldep           RelDep object the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`.
    /// @since 5.0
    void filter_provides(const Reldep & reldep, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `provides`.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.2
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_PROVIDES
    void filter_provides(const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_provides(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by their `provides`.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char **matches) - cmp_type = HY_PKG_PROVIDES
    void filter_provides(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `requires`.
    ///
    /// @param reldep_list      ReldepList with RelDep objects the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const Dependency * reldep) - cmp_type = HY_PKG_REQUIRES
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const DependencyContainer * reldeplist) - cmp_type = HY_PKG_REQUIRES
    void filter_requires(
        const ReldepList & reldep_list, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `requires`.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.2
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_REQUIRES
    void filter_requires(const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_requires(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by their `requires`.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char **matches) - cmp_type = HY_PKG_REQUIRES
    void filter_requires(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `requires`.
    ///
    /// @param package_set      PackageSet with Package objects the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const DnfPackageSet *pset) - cmp_type = HY_PKG_REQUIRES
    void filter_requires(
        const PackageSet & package_set, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `conflicts`.
    ///
    /// @param reldep_list      ReldepList with RelDep objects the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const Dependency * reldep) - cmp_type = HY_PKG_CONFLICTS
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const DependencyContainer * reldeplist) - cmp_type = HY_PKG_CONFLICTS
    void filter_conflicts(
        const ReldepList & reldep_list, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `conflicts`.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.2
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_CONFLICTS
    void filter_conflicts(const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_conflicts(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by their `conflicts`.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char **matches) - cmp_type = HY_PKG_CONFLICTS
    void filter_conflicts(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `conflicts`.
    ///
    /// @param package_set      PackageSet with Package objects the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const DnfPackageSet *pset) - cmp_type = HY_PKG_CONFLICTS
    void filter_conflicts(
        const PackageSet & package_set, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `obsoletes`.
    ///
    /// @param reldep_list      ReldepList with RelDep objects the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const Dependency * reldep) - cmp_type = HY_PKG_OBSOLETES
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const DependencyContainer * reldeplist) - cmp_type = HY_PKG_OBSOLETES
    void filter_obsoletes(
        const ReldepList & reldep_list, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `obsoletes`.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.2
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_OBSOLETES
    void filter_obsoletes(const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_obsoletes(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by their `obsoletes`.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char **matches) - cmp_type = HY_PKG_OBSOLETES
    void filter_obsoletes(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `obsoletes`.
    ///
    /// @param package_set      PackageSet with Package objects the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const DnfPackageSet *pset) - cmp_type = HY_PKG_OBSOLETES
    void filter_obsoletes(
        const PackageSet & package_set, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `recommends`.
    ///
    /// @param reldep_list      ReldepList with RelDep objects the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const Dependency * reldep) - cmp_type = HY_PKG_RECOMMENDS
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const DependencyContainer * reldeplist) - cmp_type = HY_PKG_RECOMMENDS
    void filter_recommends(
        const ReldepList & reldep_list, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `recommends`.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.2
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_RECOMMENDS
    void filter_recommends(
        const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_recommends(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by their `recommends`.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char **matches) - cmp_type = HY_PKG_RECOMMENDS
    void filter_recommends(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `recommends`.
    ///
    /// @param package_set      PackageSet with Package objects the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const DnfPackageSet *pset) - cmp_type = HY_PKG_RECOMMENDS
    void filter_recommends(
        const PackageSet & package_set, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `suggests`.
    ///
    /// @param reldep_list      ReldepList with RelDep objects the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const Dependency * reldep) - cmp_type = HY_PKG_SUGGESTS
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const DependencyContainer * reldeplist) - cmp_type = HY_PKG_SUGGESTS
    void filter_suggests(
        const ReldepList & reldep_list, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `suggests`.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.2
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_SUGGESTS
    void filter_suggests(const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_suggests(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by their `suggests`.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_SUGGESTS
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char **matches) - cmp_type = HY_PKG_SUGGESTS
    void filter_suggests(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `suggests`.
    ///
    /// @param package_set      PackageSet with Package objects the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const DnfPackageSet *pset) - cmp_type = HY_PKG_SUGGESTS
    void filter_suggests(
        const PackageSet & package_set, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `enhances`.
    ///
    /// @param reldep_list      ReldepList with RelDep objects the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const Dependency * reldep) - cmp_type = HY_PKG_ENHANCES
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const DependencyContainer * reldeplist) - cmp_type = HY_PKG_ENHANCES
    void filter_enhances(
        const ReldepList & reldep_list, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `enhances`.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.2
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_ENHANCES
    void filter_enhances(const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_enhances(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by their `enhances`.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char **matches) - cmp_type = HY_PKG_ENHANCES
    void filter_enhances(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `enhances`.
    ///
    /// @param package_set      PackageSet with Package objects the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const DnfPackageSet *pset) - cmp_type = HY_PKG_ENHANCES
    void filter_enhances(
        const PackageSet & package_set, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `supplements`.
    ///
    /// @param reldep_list      ReldepList with RelDep objects the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const Dependency * reldep) - cmp_type = HY_PKG_SUPPLEMENTS
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const DependencyContainer * reldeplist) - cmp_type = HY_PKG_SUPPLEMENTS
    void filter_supplements(
        const ReldepList & reldep_list, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `supplements`.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.2
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_SUPPLEMENTS
    void filter_supplements(
        const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_supplements(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by their `supplements`.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char **matches) - cmp_type = HY_PKG_SUPPLEMENTS
    void filter_supplements(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `supplements`.
    ///
    /// @param package_set      PackageSet with Package objects the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const DnfPackageSet *pset) - cmp_type = HY_PKG_SUPPLEMENTS
    void filter_supplements(
        const PackageSet & package_set, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by `files` they contain.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`, `IEXACT`, `NOT_IEXACT`, `ICONTAINS`, `NOT_ICONTAINS`, `IGLOB`, `NOT_IGLOB`, `CONTAINS`, `NOT_CONTAINS`.
    /// @since 5.2
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_FILE
    void filter_file(const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_file(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by `files` they contain.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`, `IEXACT`, `NOT_IEXACT`, `ICONTAINS`, `NOT_ICONTAINS`, `IGLOB`, `NOT_IGLOB`, `CONTAINS`, `NOT_CONTAINS`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char **matches) - cmp_type = HY_PKG_FILE
    void filter_file(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by their `location`.
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`.
    /// @since 5.2
    //
    // TODO(dmach): enable glob match to enable filename matching: {nevra.rpm, */nevra.rpm}
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_LOCATION
    void filter_location(const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_location(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by their `location`.
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`.
    /// @since 5.0
    //
    // TODO(dmach): enable glob match to enable filename matching: {nevra.rpm, */nevra.rpm}
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char **matches) - cmp_type = HY_PKG_LOCATION
    void filter_location(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by `id` of the Repo they belong to.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.2
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char *match) - cmp_type = HY_PKG_REPONAME
    void filter_repo_id(const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_repo_id(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filter packages by `id` of the Repo they belong to.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const char **matches) - cmp_type = HY_PKG_REPONAME
    void filter_repo_id(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filters packages by the `id` of the repository they were installed from.
    /// This also removes any packages from the query that are not currently installed.
    ///
    /// @param pattern          A string the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.2.14
    //
    void filter_from_repo_id(
        const std::string & pattern, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ) {
        filter_from_repo_id(std::vector<std::string>{pattern}, cmp_type);
    };

    /// Filters packages by the `id` of the repository they were installed from.
    /// This also removes any packages from the query that are not currently installed.
    ///
    /// @param patterns         A vector of strings the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GLOB`, `NOT_GLOB`.
    /// @since 5.2.14
    //
    void filter_from_repo_id(
        const std::vector<std::string> & patterns, libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by advisories they are included in.
    ///
    /// @param advisory_query   AdvisoryQuery with Advisories that contain package lists the filter is matched against.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GT`, `GTE`, `LT`, `LTE`.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, const DnfPackageSet *pset) - cmp_type = HY_PKG_ADVISORY/_BUG/_CVE/_SEVERITY/_TYPE
    void filter_advisories(
        const libdnf5::advisory::AdvisoryQuery & advisory_query,
        libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::EQ);

    /// Filter packages by the advisories they are included in, considering
    /// only the latest advisories that are not resolved in the currently
    /// installed package set.
    ///
    /// @param advisory_query   AdvisoryQuery with Advisories that contain package lists the filter is matched against.
    /// @param installed        PackageQuery with currently installed packages.
    /// @param cmp_type         A comparison (match) operator, defaults to `QueryCmp::EQ`.
    ///                         Supported values: `EQ`, `NEQ`, `GT`, `GTE`, `LT`, `LTE`.
    /// @since 5.0
    void filter_latest_unresolved_advisories(
        const libdnf5::advisory::AdvisoryQuery & advisory_query,
        PackageQuery & installed,
        libdnf5::sack::QueryCmp cmp_type = libdnf5::sack::QueryCmp::GTE);

    /// Filter installed packages.
    ///
    /// Removes from the query all packages that are not installed.
    /// @since 5.0
    // @replaces libdnf/sack/query.hpp:method:installed()
    void filter_installed();

    /// Filter available packages.
    ///
    /// Removes from the query all packages that are installed.
    /// @since 5.0
    // @replaces libdnf/sack/query.hpp:method:available()
    void filter_available();

    /// Filter available packages that are upgrades to installed packages.
    ///
    /// Removes from the query all packages that are not upgrades to installed packages.
    /// @since 5.0
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, int match) - cmp_type = HY_PKG_UPGRADES
    void filter_upgrades();

    /// Filter available packages that are downgrades to installed packages.
    ///
    /// Removes from the query all packages that are not downgrades to installed packages.
    /// @since 5.0
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, int match) - cmp_type = HY_PKG_DOWNGRADES
    void filter_downgrades();

    /// Filter installed packages for which there are available upgrades.
    ///
    /// Only installed packages remain in the query, and only those for which upgrades are available.
    /// @since 5.0
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, int match) - cmp_type = HY_PKG_UPGRADABLE
    void filter_upgradable();

    /// Filter installed packages for which there are available downgrades.
    ///
    /// Only installed packages remain in the query, and only those for which downgrades are available.
    /// @since 5.0
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, int match) - cmp_type = HY_PKG_DOWNGRADABLE
    void filter_downgradable();

    /// Group packages by `name` and `arch`. Then within each group, keep packages that correspond with up to `limit` of (all but) latest `evr`s in the group.
    ///
    /// @param limit            If `limit` > 0, keep `limit` number `evr`s in each group.
    ///                         If `limit` < 0, keep all **but** `limit` last `evr`s in each group.
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, int match) - cmp_type = HY_PKG_LATEST
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, int match) - cmp_type = HY_PKG_LATEST_PER_ARCH
    void filter_latest_evr(int limit = 1);

    /// Group packages by `name`. Then within each group, keep packages that correspond with up to `limit` of (all but) latest `evr`s in the group.
    ///
    /// @param limit            If `limit` > 0, keep `limit` number `evr`s in each group.
    ///                         If `limit` < 0, keep all **but** `limit` last `evr`s in each group.
    /// @since 5.2
    void filter_latest_evr_any_arch(int limit = 1);

    /// Group packages by `name` and `arch`. Then within each group, keep packages that correspond with up to `limit` of (all but) earliest `evr`s in the group.
    ///
    /// @param limit            If `limit` > 0, keep `limit` number `evr`s in each group.
    ///                         If `limit` < 0, keep all **but** `limit` last `evr`s in each group.
    /// @since 5.0
    void filter_earliest_evr(int limit = 1);

    /// Group packages by `name`. Then within each group, keep packages that correspond with up to `limit` of (all but) earliest `evr`s in the group.
    ///
    /// @param limit            If `limit` > 0, keep `limit` number `evr`s in each group.
    ///                         If `limit` < 0, keep all **but** `limit` last `evr`s in each group.
    /// @since 5.2
    void filter_earliest_evr_any_arch(int limit = 1);

    /// Group packages by `name` and `arch`. Then within each group, keep packages that belong to a repo with the highest priority (the lowest number).
    /// The filter works only on available packages, installed packages are not affected.
    ///
    /// @since 5.0
    //
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, int match) - cmp_type = HY_PKG_UPGRADES_BY_PRIORITY
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, int match) - cmp_type = HY_PKG_OBSOLETES_BY_PRIORITY
    // @replaces libdnf/sack/query.hpp:method:addFilter(int keyname, int cmp_type, int match) - cmp_type = HY_PKG_LATEST_PER_ARCH_BY_PRIORITY
    // TODO(dmach): consider removing the installed packages during the filtering
    void filter_priority();

    /// Keep in the query only packages that are installed but not available in any
    /// enabled repository. Even excluded packages (e.g. using excludepkgs config
    /// option) are considered as available in repositories for the purpose of extras
    /// calculation.
    /// Those installed packages that are only part of non-active modules are also
    /// considered as extras.
    /// @param exact_evr If false (default) extras calculation is based only on
    ///                  `name.arch`. That means package is not in extras if any version
    ///                  of the package exists in any of the enabled repositories.
    ///                  If true, filter_extras is more strict and returns each package
    ///                  which exact NEVRA is not present in any enabled repository.
    void filter_extras(const bool exact_evr = false);

    /// Keep in the query only recent packages - those with build time after given timestamp
    /// @param timestamp Only packages built after this will pass
    void filter_recent(const time_t timestamp);

    /// Keep in the query only installed packages that are user-installed.
    void filter_userinstalled();

    /// Filter unneeded packages. Unneeded packages are those which are installed as
    /// dependencies and are not required by any user-installed package any more.
    void filter_unneeded();

    /// Filter unneeded packages without protected packages. Unneeded not protected packages are those
    /// which are installed as dependencies and are not required by any user-installed or protected package
    /// any more and are not protected them self.
    void filter_unneeded_not_protected();

    /// Resolve spec according to provided settings. It tests whether spec is NEVRA type, provide, file or binary.
    /// It returns only the first match type. If spec has a match as NEVRA and provide type it only keeps matches with
    /// the first tested type (NEVRA).
    // TODO(jmracek) return std::pair<bool, std::unique_ptr<libdnf5::rpm::Nevra>>
    // @replaces libdnf/sack/query.hpp:method:std::pair<bool, std::unique_ptr<Nevra>> filterSubject(const char * subject, HyForm * forms, bool icase, bool with_nevra, bool with_provides, bool with_filenames);
    std::pair<bool, libdnf5::rpm::Nevra> resolve_pkg_spec(
        const std::string & pkg_spec, const libdnf5::ResolveSpecSettings & settings, bool with_src);

    /// Returns `true` if the dependency `reldep` is satisfied by the packages in query, otherwise `false` is returned.
    /// @since 5.3.0.1
    bool is_dep_satisfied(const Reldep & reldep);

    void swap(PackageQuery & other) noexcept;

    /// Filter packages to keep only duplicates of installed packages. Packages are duplicate if they have the same `name` and `arch` but different `evr`.
    void filter_duplicates();

    /// Filter the leaf packages.
    ///
    /// Leaf packages are installed packages that are not required as a dependency of another installed package.
    /// However, two or more installed packages might depend on each other in a dependency cycle. Packages
    /// in such cycles that are not required by any other installed package are also leaf.
    void filter_leaves();

    /// Filter packages whose installation or upgrade should cause a system
    /// reboot to be recommended. These are packages that either (1) belong to
    /// a hardcoded set of "core packages", including the kernel and systemd,
    /// or (2) have an associated `reboot_suggested` advisory.
    void filter_reboot_suggested();

    /// Filter the leaf packages and return them grouped by their dependencies.
    ///
    /// Leaf packages are installed packages that are not required as a dependency of another installed package.
    /// However, two or more installed packages might depend on each other in a dependency cycle. Packages
    /// in such cycles that are not required by any other installed package are also leaf.
    /// Packages in such cycles form a group of leaf packages.
    ///
    /// @return  Groups of one or more interdependent leaf packages.
    std::vector<std::vector<Package>> filter_leaves_groups();

    /// Filter installonly packages.
    ///
    /// Filter packages that provide a capability that matches with any value in installonlypkgs configuration option.
    void filter_installonly();

    /// Filter out versionlock excluded packages.
    ///
    /// The packages versions excluded by versionlock are removed from the query.
    /// @since 5.1.13
    void filter_versionlock();

private:
    LIBDNF_LOCAL std::vector<std::vector<Package>> filter_leaves(bool return_grouped_leaves);

    friend libdnf5::Goal;

    class LIBDNF_LOCAL PQImpl;
    std::unique_ptr<PQImpl> p_pq_impl;
};


}  // namespace libdnf5::rpm

#endif  // LIBDNF5_RPM_PACKAGE_QUERY_HPP
