Mailinglist Archive: yast-devel (157 mails)

< Previous Next >
[yast-devel] [RFC] QueryBuilder and (Resolvable)Query
  • From: Jan Kupec <jkupec@xxxxxxx>
  • Date: Fri, 29 Jun 2007 15:14:48 +0200
  • Message-id: <468505C8.3010905@xxxxxxx>
Hi!

Here is my proposal of a new libzypp API for various metadata queries.
It should be useful for YaST package managers, zypper, YaST online
update and maybe others. Pease see attached QueryBuilder.h file and
comment on the design and usability.

QueryBuilder is meant to build an sqlite query for libzypp's metadata
cache database and to be used by
ResolvableQuery::query(QueryBuilder,ProcessingFunctor) function (or
other Query class) to do complex resolvable data queries. Result of
these queries will be processed by ProcessingFunctor (read on).

The reason to create such an API is to have a convenient API for coding
various kinds of user queries, so that apps using libzypp don't have to
code the functionality by themselves by traversing the resolvable pool.
And since we (will hopefully) have the new metadata cache database,
there is another reason: to make use of the database to speed up the
search and save memory requirements (don't load the pool, just query the
database). I would have to code it once in zypper anyway, so this way it
can be reused by others as well.


CODE EXAMPLE:

//////// code START /////////////////////////////////////////

bool is_regexp;        // treat the search string as regexp?
bool search_summaries; // search also in summaries?
string search_string;  // user given search string
Resolvable::Kind kind; // the result will be limited to this kind
<snip>
zypp::cache::QueryBuilder builder;

builder.addName(search_string, is_regexp);
if (search_summaries)
  builder.addAttribute(zypp::cache::attrResObjectSummary(),
                       search_string, is_regexp);
builder.addKind(kind);

zypp::cache::ResolvableQuery resquery;
resquery.query(builder, processing_functor);

//////// code END /////////////////////////////////////////

(the functor is
function<bool( const data::RecordId &, data::ResObject_Ptr )>
we can provide one which would use Selectables (or NameKindProxy) for
yast as well)


FEATURES

- search by name, any cache attribute, kind, (future: installed status),
  version
- uses simple strings or regexes
- search by dependencies (select resolvables which are required
  by e.g. pattern X)
- use multiple search conditions and choose to require all or any
  of them satisfied.

IMPLEMENTATION

- based on given arguments and options, an sqlite command will be built
  This command will be executed by a ResolvableQuery::query() or another
  Query class (see attachment - just a stub).

- i decided to write field values into the sqlite command string itself.
  Using variable names and bind values to them would be too complex.

- regexes - sqlite's REGEXP keyword will be used, bound to user
  (libzypp) defined regexp matching function of our liking.


ISSUES

- what regexp syntax do we want to support?
- something missing/to be changed in the API?


Cheers,

Jano

#ifndef ZYPP_CACHE_QUERYBUILDER_H
#define ZYPP_CACHE_QUERYBUILDER_H

#include <string>
#include <boost/logic/tribool.hpp>

#include "zypp/Edition.h"
#include "zypp/Rel.h"

#include "zypp/Resolvable.h"
#include "zypp/Dep.h"

namespace zypp
{
  namespace cache
  {


  /**
   * Level of matching of substrings in text attributes.
   */
  enum MatchLevel
  {
    MATCH_ANY_SUBSTRING, //! implemented by <tt>like '%value%'</tt> or <tt>regexp '.*value.*'</tt>
    MATCH_WHOLE_WORDS,   //! impelmented by <tt>regexp '.*\bvalue\b.*'</tt>
    MATCH_EXACT_PHRASE   //! implemented by <tt>= 'value'</tt> or <tt>regexp 'value'</tt>
  };

  /**
   * Resolvable query builder for ZYpp sqlite cache database.
   */
  class QueryBuilder
  {
  public:
    /**
     * Set resolvable kind filter. If more kinds are added, they are always
     * ORed (\ref setRequireAll() does not affect this).
     */
    void addKind(const Resolvable::Kind & kind);

    /**
     * Add resolvable name filter. If \a is_regexp is <tt>true</tt>, the
     * \a name argument is treated as a regexp.
     * 
     * \see setMatchLevel()
     * \see setCaseSensitive()
     * \see setRequireAll()
     */
    void addName(const std::string & name, bool is_regexp = false);
    
    /**
     * Add a cache attribute filter. See \ref zypp::cache::CacheAttributes for
     * the list of attribute objects which you can use.
     * If \a is_regexp is <tt>true</tt>, the \a value argument is treated as
     * a regexp.
     * 
     * \see zypp::cache::CacheAttributes
     * \see setMatchLevel()
     * \see setCaseSensitive()
     * \see setRequireAll()
     * \see setLocale()
     */
    void addAttribute(const cache::Attribute & attr, const std::string & value, bool is_regexp = false);
    
    /**
     * Set installed status filter.
     * 
     * \param value if <tt>true</tt>/<tt>false</tt>, match only
     *              installed/uninstalled resolvables. If <tt>indeterminate</tt>
     *              match all (default in QueryBuilder ctor).
     * 
     * \todo We need to merge target and repo resolvables in the cache and
     *       mark the intersection as installed resolvables for this filter
     *       to work. Otherwise we need to search twice (in target and in repo).
     */
    void setInstalled(tribool value = true);

    /**
     * Set edition filter. Match resolvalbes with editions according to
     * \a edition and \a rel.
     * 
     * \param edition
     * \param rel operand
     */
    void setEdition(const Edition & edition, const Rel & rel = Rel::EQ);

    /**
     * Add dependency filter.
     * 
     * \param dtype depenedcy type
     * \param name depenency name
     * \param edition edition for a versioned dependency
     * \param rel operand for a versioned dependency
     * \param pre prerequired dependency flag
     * 
     * \todo maybe a is_regexp bool as in addName() for the name parameter would
     *       be handy here as well.
     * \todo add more addDependecy() variants
     */
    void addDependency(const Dep & dtype,
                       const std::string & name,
                       const Edition & edition = Edition(),
                       const Rel & rel = Rel::EQ,
                       tribool pre = false);

    /**
     * Require that all filter conditions must be met.
     * 
     * \note This does not apply to <b>kind</b>. If more than one kind is
     *       given, the query returns all given kinds.
     */
    void setRequireAll(const bool require_all = true) { _require_all = require_all; }

    /**
     * Match if any of the filter conditions is met. This is the default.
     */
    void setRequireAny(const bool require_any = true) { _require_all = !require_any; }


    /** \name Text Attributes Matching Options */
    //@{
    void setCaseSensitive(const bool value = true);
    void setMatchLevel(const MatchLevel level) { _match_level = level; }
    void setLocale(const Locale & locale);
    //@}

    /** Build an sqlite query according to options and arguments set. */
    void buildQuery();

    /**
     * \name Generated Sqlite Query Getters
     * 
     * The partial query getters (select(), from(), where(), etc) can be
     * used to customize the resulting query.
     */
    //@{

    /**
     * Return the complete sqlite statement as string.
     */
    const std::string & query() const;

    /**
     * Return the <tt>select</tt> part of the statement.
     */
    const std::string & select() const;
    
    /**
     * Return the <tt>from</tt> part of the statement.
     */
    const std::string & from() const;

    /**
     * Return the <tt>where</tt> part of the statement.
     */
    const std::string & where() const;

    /**
     * Return the <tt>order by</tt> part of the statement.
     */
    const std::string & orderby() const;
    //@}

  private:
    /** Implementation */
    class Impl;
    /** Pointer to implementation */
    RW_pointer<Impl,rw_pointer::Scoped<Impl> > _pimpl;
  }


  } // ns cache
} // ns zypp

#endif /*ZYPP_CACHE_QUERYBUILDER_H*/
#ifndef ZYPP_QUERY_H_
#define ZYPP_QUERY_H_

#include <string>

#include "zypp/cache/QueryBuilder.h"

namespace zypp
{


  class Query
  {
  public:

    /**
     * Callback definition
     * first parameter is the resolvable id.
     * second parameter is a \ref data::ResObject data object with the resource
     */
    typedef function<bool(const data::RecordId &, const data::ResObject_Ptr & )>
        ProcessResolvable;

    typedef unsigned long long ResultSize;

    /**
     * Ctor.
     */
    Query();

    /**
     * Dtor.
     */
    ~Query();

    /**
     * Builds query and executes it.
     *
     * \throws cache::QueryBuildException 
     */
    void doQuery(cache::QueryBuilder & qbuilder, const ProcessResolvable & fnc);

    /**
     * Builds count query and executes it.
     *
     * \return Number of items matching the filter.
     * \throws query::BuildException 
     */
    ResultSize doQueryCount(); 


    ResultSize resultSize() const;

  private:
    class Impl;
    RW_pointer<Impl,rw_pointer::Scoped<Impl> > _pimpl;
  };

} // ns zypp

#endif /*ZYPP_QUERY_H_*/
< Previous Next >
List Navigation
This Thread
  • No further messages