BOOST_CHECK_EQUAL( res.subFind( sat::SolvAttr::updateReferenceHref ), res.subFind( "href" ) );
BOOST_CHECK_EQUAL( res.subFind( sat::SolvAttr::updateReferenceId ), res.subFind( "id" ) );
BOOST_CHECK_EQUAL( res.subFind( sat::SolvAttr::updateReferenceTitle ), res.subFind( "title" ) );
+
+ // NOTE: Unfortunately the satsolver dataiterator loses constect information when
+ // entering a sub-structure. That's why one can't invoke e.g subBegin on an iterator
+ // that was retieved by subFind.
+ // The test below will fail, once libsatsolver fixes the dataiterator. The expected
+ // result then is, that subBegin brings you to the beginning again.
+ BOOST_CHECK_EQUAL( res.subFind( sat::SolvAttr::updateReferenceType ).subBegin(), res.subEnd() );
+ // BOOST_CHECK_EQUAL( res.subFind( sat::SolvAttr::updateReferenceType ).subBegin(), res.subBegin() );
}
+
+ // search substructure id without parent-structure won't work:
+ q = sat::LookupAttr( sat::SolvAttr::updateReferenceId );
+ BOOST_CHECK_EQUAL( q.size(), 0 );
+
+ // search id in parent-structure:
+ q = sat::LookupAttr( sat::SolvAttr::updateReferenceId, sat::SolvAttr::updateReference );
+ BOOST_CHECK_EQUAL( q.size(), 303 );
+
+ // search id in any parent-structure:
+ q = sat::LookupAttr( sat::SolvAttr::updateReferenceId, sat::SolvAttr::allAttr );
+ BOOST_CHECK_EQUAL( q.size(), 303 );
+
+ // search any id in parent-structure: (4 ids per updateReference)
+ q = sat::LookupAttr( sat::SolvAttr::allAttr, sat::SolvAttr::updateReference );
+ BOOST_CHECK_EQUAL( q.size(), 1212 );
+
+ // search any id in any parent-structure:
+ q = sat::LookupAttr( sat::SolvAttr::allAttr, sat::SolvAttr::allAttr );
+ BOOST_CHECK_EQUAL( q.size(), 10473 );
}
BOOST_AUTO_TEST_CASE(LookupAttr_repoattr)
Impl()
{}
Impl( SolvAttr attr_r, Location loc_r )
- : _attr( attr_r ), _solv( loc_r == REPO_ATTR ? SOLVID_META : noSolvableId )
+ : _attr( attr_r ), _parent( SolvAttr::noAttr ), _solv( loc_r == REPO_ATTR ? SOLVID_META : noSolvableId )
{}
Impl( SolvAttr attr_r, Repository repo_r, Location loc_r )
- : _attr( attr_r ), _repo( repo_r ), _solv( loc_r == REPO_ATTR ? SOLVID_META : noSolvableId )
+ : _attr( attr_r ), _parent( SolvAttr::noAttr ), _repo( repo_r ), _solv( loc_r == REPO_ATTR ? SOLVID_META : noSolvableId )
{}
Impl( SolvAttr attr_r, Solvable solv_r )
- : _attr( attr_r ), _solv( solv_r )
+ : _attr( attr_r ), _parent( SolvAttr::noAttr ), _solv( solv_r )
{}
public:
_solv = solv_r;
}
+ SolvAttr parent() const
+ { return _parent; }
+
+ void setParent( SolvAttr attr_r )
+ { _parent = attr_r; }
+
+ public:
LookupAttr::iterator begin() const
{
if ( _attr == SolvAttr::noAttr || sat::Pool::instance().reposEmpty() )
whichRepo = _repo.id();
detail::DIWrap dip( whichRepo, _solv.id(), _attr.id(), _attrMatcher.searchstring(), _attrMatcher.flags().get() );
+ if ( _parent != SolvAttr::noAttr )
+ ::dataiterator_prepend_keyname( dip.get(), _parent.id() );
return iterator( dip ); // iterator takes over ownership!
}
private:
SolvAttr _attr;
+ SolvAttr _parent;
Repository _repo;
Solvable _solv;
AttrMatcher _attrMatcher;
LookupAttr::LookupAttr( SolvAttr attr_r, Location loc_r )
: _pimpl( new Impl( attr_r, loc_r ) )
{}
+ LookupAttr::LookupAttr( SolvAttr attr_r, SolvAttr parent_r, Location loc_r )
+ : _pimpl( new Impl( attr_r, loc_r ) )
+ { _pimpl->setParent( parent_r ); }
LookupAttr::LookupAttr( SolvAttr attr_r, Repository repo_r, Location loc_r )
: _pimpl( new Impl( attr_r, repo_r, loc_r ) )
{}
+ LookupAttr::LookupAttr( SolvAttr attr_r, SolvAttr parent_r, Repository repo_r, Location loc_r )
+ : _pimpl( new Impl( attr_r, repo_r, loc_r ) )
+ { _pimpl->setParent( parent_r ); }
LookupAttr::LookupAttr( SolvAttr attr_r, Solvable solv_r )
: _pimpl( new Impl( attr_r, solv_r ) )
{}
+ LookupAttr::LookupAttr( SolvAttr attr_r, SolvAttr parent_r, Solvable solv_r )
+ : _pimpl( new Impl( attr_r, solv_r ) )
+ { _pimpl->setParent( parent_r ); }
+
///////////////////////////////////////////////////////////////////
void LookupAttr::setSolvable( Solvable solv_r )
{ _pimpl->setSolvable( solv_r ); }
+ SolvAttr LookupAttr::parent() const
+ { return _pimpl->parent(); }
+
+ void LookupAttr::setParent( SolvAttr attr_r )
+ { _pimpl->setParent( attr_r ); }
+
///////////////////////////////////////////////////////////////////
LookupAttr::iterator LookupAttr::begin() const
return false;
}
- bool LookupAttr::iterator::solvAttrSubEntry() const
+ ///////////////////////////////////////////////////////////////////
+ namespace
{
- return solvAttrType() == REPOKEY_TYPE_FLEXARRAY;
+ enum SubType { ST_NONE, // no sub-structure
+ ST_FLEX, // flexarray
+ ST_SUB }; // inside sub-structure
+ SubType subType( const detail::DIWrap & dip )
+ {
+ if ( ! dip )
+ return ST_NONE;
+ if ( dip.get()->key->type == REPOKEY_TYPE_FLEXARRAY )
+ return ST_FLEX;
+ return dip.get()->kv.parent ? ST_SUB : ST_NONE;
+ }
}
+ ///////////////////////////////////////////////////////////////////
+
+ bool LookupAttr::iterator::solvAttrSubEntry() const
+ { return subType( _dip ) != ST_NONE; }
///////////////////////////////////////////////////////////////////
// Iterate sub-structures.
LookupAttr::iterator LookupAttr::iterator::subBegin() const
{
- if ( ! solvAttrSubEntry() )
- return subEnd();
-
- // remember this position
- ::dataiterator_setpos( _dip.get() );
-
+ switch ( subType( _dip ) )
+ {
+ case ST_NONE:
+ return subEnd();
+ break;
+ case ST_FLEX:
+ ::dataiterator_setpos( _dip.get() );
+ break;
+ case ST_SUB:
+ ::dataiterator_setpos_parent( _dip.get() );
+ break;
+ }
// setup the new sub iterator with the remembered position
detail::DIWrap dip( 0, SOLVID_POS, 0, 0, 0 );
return iterator( dip ); // iterator takes over ownership!
if ( attrname_r.empty() )
return subBegin();
+ SubType subtype( subType( _dip ) );
+ if ( subtype == ST_NONE )
+ return subBegin();
+
std::string subattr( inSolvAttr().asString() );
- subattr += ":";
- subattr += attrname_r;
+ if ( subtype == ST_FLEX )
+ {
+ // append ":attrname"
+ subattr += ":";
+ subattr += attrname_r;
+ }
+ else
+ {
+ // replace "oldname" after ':' with "attrname"
+ std::string::size_type pos( subattr.rfind( ':' ) );
+ if ( pos != std::string::npos )
+ {
+ subattr.erase( pos+1 );
+ subattr += attrname_r;
+ }
+ else
+ subattr = attrname_r; // no ':' so replace all.
+ }
return subFind( SolvAttr( subattr ) );
}
{
str << " " << it.inSolvAttr() << " = " << it.asString() << endl;
}
- str << "}" << endl;
+ str << "}";
return str.str();
}
break;
else if ( obj.inRepo() )
str << obj.inRepo();
- str << '<' << obj.inSolvAttr()
- << ">(" << IdString(obj.solvAttrType()) << ") = " << obj.asString();
+ str << '<' << obj.inSolvAttr() << (obj.solvAttrSubEntry() ? ">(*" : ">(")
+ << IdString(obj.solvAttrType()) << ") = " << obj.asString();
return str;
}
*
* Use \ref SolvAttr::allAttr to search all attributes.
*
+ * To search for attributes located in a sub-structure (flexarray)
+ * you also have to pass the sub-structures attribute as parent.
+ * Passing \ref SolvAttr::allAttr a parent will lookup the attribute
+ * in \c any sub-structure.
+ *
+ * \code
+ * // Lookup all 'name' attributes:
+ * sat::LookupAttr q( sat::SolvAttr::name );
+ * // Lookup all 'name' attributes within a sub-structure 'data':
+ * sat::LookupAttr q( sat::SolvAttr::name, sat::SolvAttr::data );
+ * // Lookup all 'name' attributes within any sub-structure:
+ * sat::LookupAttr q( sat::SolvAttr::name, sat::SolvAttr::allAttr );
+ * \endcode
+ *
* \code
* // look for all attributes of one solvable
* void ditest( sat::Solvable slv_r )
/** Lookup \ref SolvAttr in \ref Pool (all repositories). */
explicit LookupAttr( SolvAttr attr_r, Location = SOLV_ATTR );
+ /** \overload SolvAttr within sub-structure \a parent_r. */
+ LookupAttr( SolvAttr attr_r, SolvAttr parent_r, Location = SOLV_ATTR );
/** Lookup \ref SolvAttr in one\ref Repository. */
- explicit LookupAttr( SolvAttr attr_r, Repository repo_r, Location = SOLV_ATTR );
+ LookupAttr( SolvAttr attr_r, Repository repo_r, Location = SOLV_ATTR );
+ /** \overload SolvAttr within sub-structure \a parent_r. */
+ LookupAttr( SolvAttr attr_r, SolvAttr parent_r, Repository repo_r, Location = SOLV_ATTR );
/** Lookup \ref SolvAttr in one \ref Solvable. */
LookupAttr( SolvAttr attr_r, Solvable solv_r );
+ /** \overload SolvAttr within sub-structure \a parent_r. */
+ LookupAttr( SolvAttr attr_r, SolvAttr parent_r, Solvable solv_r );
public:
/** \name Search result. */
/** Set search in one \ref Solvable. */
void setSolvable( Solvable solv_r );
+
+ /** Whether to search within a sub-structure (\ref SolvAttr::noAttr if not) */
+ SolvAttr parent() const;
+
+ /** Set search within a sub-structure (\ref SolvAttr::noAttr for none) */
+ void setParent( SolvAttr attr_r );
//@}
private:
/** The current \ref SolvAttr. */
SolvAttr inSolvAttr() const;
- /** Whether this points to the end of a query. */
+ /** Whether this points to the end of a query (Iterator is invalid). */
bool atEnd() const
{ return !_dip; }
//@}
*
* These are usable iff \ref solvAttrSubEntry is \c true.
*
+ * \note Unfortunately the underlying satsolver dataiterator as returned
+ * by \ref subBegin and \ref subFind loses some context when being created.
+ * Thus it's not possible to invoke \ref subBegin and \ref subFind on an
+ * iterator that was previously returned by one of those methods. The result
+ * will be an \c end iterator. For the same reason it is not possible for an
+ * iterator to leave the sub-structure again.
+ *
* \code
* // Lookup all "update:reference" entries for a specific solvable
* sat::LookupAttr q( sat::SolvAttr::updateReference, p->satSolvable() );