
/*
 * This is an auto-generated file.
 * Do not edit! All changes made to it will be lost.
 */


#include <entities.h>
#include <storage/datastore.h>
#include <storage/selectquerybuilder.h>
#include <utils.h>

#include <qsqldatabase.h>
#include <QLatin1String>
#include <qsqlquery.h>
#include <qsqlerror.h>
#include <qvariant.h>
#include <QtCore/QHash>
#include <QtCore/QMutex>

using namespace Akonadi::Server;



// private class
class SchemaVersion::Private : public QSharedData
{
  public:
    Private() : QSharedData()
    
      , version( 0 )
    
      , version_changed( false )
    
    {}

    
    int version;
    
    bool version_changed : 1;
    

    static void addToCache( const SchemaVersion & entry );

    // cache
    static bool cacheEnabled;
    static QMutex cacheMutex;
    
};


// static members
bool SchemaVersion::Private::cacheEnabled = false;
QMutex SchemaVersion::Private::cacheMutex;



void SchemaVersion::Private::addToCache( const SchemaVersion & entry )
{
  Q_ASSERT( cacheEnabled );
  Q_UNUSED( entry ); 
  cacheMutex.lock();
  
  cacheMutex.unlock();
}


// constructor
SchemaVersion::SchemaVersion() : Entity(),
  d( new Private )
{
}

SchemaVersion::SchemaVersion(
  int version
) :
  Entity(),
  d( new Private )
{

  d->version = version;
  d->version_changed = true;

}

SchemaVersion::SchemaVersion( const SchemaVersion & other )
  : Entity( other ), d( other.d )
{
}

// destructor
SchemaVersion::~SchemaVersion() {}

// assignment operator
SchemaVersion& SchemaVersion::operator=( const SchemaVersion & other )
{
  if ( this != &other ) {
    d = other.d;
    setId( other.id() );
  }
  return *this;
}

// comparisson operator
bool SchemaVersion::operator==( const SchemaVersion & other ) const
{
  return id() == other.id();
}

// accessor methods
int SchemaVersion::version() const
{
  return d->version;
}

void SchemaVersion::
setVersion( int version )

{
  d->version = version;
  d->version_changed = true;
}



// SQL table information
QString SchemaVersion::tableName()
{
  return QLatin1String( "SchemaVersionTable" );
}

QStringList SchemaVersion::columnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "version" ) );
  
  return rv;
}

QStringList SchemaVersion::fullColumnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "SchemaVersionTable.version" ) );
  
  return rv;
}


QString SchemaVersion::versionColumn()
{
  return QLatin1String( "version" );
}

QString SchemaVersion::versionFullColumnName()
{
  return tableName() + QLatin1String( ".version" );
}



// count records
int SchemaVersion::count( const QString &column, const QVariant &value )
{
  return Entity::count<SchemaVersion>( column, value );
}

// check existence



// result extraction
QVector< SchemaVersion > SchemaVersion::extractResult( QSqlQuery & query )
{
  QVector<SchemaVersion> rv;
  while ( query.next() ) {
    rv.append( SchemaVersion(
      
        (query.isNull(0)) ?
          int() :
          
          query.value( 0 ).value<int>()
            
    ) );
  }
  return rv;
}

// data retrieval


QVector<SchemaVersion> SchemaVersion::retrieveAll()
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<SchemaVersion>();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of all records from table" << tableName()
      << qb.query().lastError().text() << qb.query().lastQuery();
    return QVector<SchemaVersion>();
  }
  return extractResult( qb.query() );
}

QVector<SchemaVersion> SchemaVersion::retrieveFiltered( const QString &key, const QVariant &value )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<SchemaVersion>();

  SelectQueryBuilder<SchemaVersion> qb;
  if ( value.isNull() )
    qb.addValueCondition( key, Query::Is, QVariant() );
  else
    qb.addValueCondition( key, Query::Equals, value );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of records from table" << tableName()
      << "filtered by" << key << "=" << value
      << qb.query().lastError().text();
    return QVector<SchemaVersion>();
  }
  return qb.result();
}

// data retrieval for referenced tables


// data retrieval for inverse referenced tables


#ifndef QT_NO_DEBUG_STREAM
// debug stream operator
QDebug & operator<<( QDebug& d, const SchemaVersion& entity )
{
  d << "[SchemaVersion: "
  
    << "version = " << entity.version()
    
    << "]";
  return d;
}
#endif

// inserting new data
bool SchemaVersion::insert( qint64* insertId )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Insert );
  
    if ( d->version_changed )
      qb.setColumnValue( versionColumn(), this->version() );
    

  if ( !qb.exec() ) {
    akDebug() << "Error during insertion into table" << tableName()
      << qb.query().lastError().text();
    return false;
  }

  setId( qb.insertId() );
  if ( insertId )
    *insertId = id();
  return true;
}

bool SchemaVersion::hasPendingChanges() const
{
  return false
  
    || d->version_changed
  ;
}

// update existing data
bool SchemaVersion::update()
{
  invalidateCache();
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Update );

  
    if ( d->version_changed ) {
      
      qb.setColumnValue( versionColumn(), this->version() );
    }
  

  if ( !qb.exec() ) {
    akDebug() << "Error during updating record with id" << id()
             << " in table" << tableName() << qb.query().lastError().text();
    return false;
  }
  return true;
}

// delete records
bool SchemaVersion::remove( const QString &column, const QVariant &value )
{
  invalidateCompleteCache();
  return Entity::remove<SchemaVersion>( column, value );
}



// cache stuff
void SchemaVersion::invalidateCache() const
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::cacheMutex.unlock();
  }
}

void SchemaVersion::invalidateCompleteCache()
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::cacheMutex.unlock();
  }
}

void SchemaVersion::enableCache( bool enable )
{
  Private::cacheEnabled = enable;
}



// private class
class Resource::Private : public QSharedData
{
  public:
    Private() : QSharedData()
    
      , name()
    
      , isVirtual( false )
    
      , name_changed( false )
    
      , isVirtual_changed( false )
    
    {}

    
    QString name;
    
    bool isVirtual : 1;
    
    bool name_changed : 1;
    
    bool isVirtual_changed : 1;
    

    static void addToCache( const Resource & entry );

    // cache
    static bool cacheEnabled;
    static QMutex cacheMutex;
    
    static QHash<qint64, Resource > idCache;
    
    static QHash<QString, Resource > nameCache;
    
};


// static members
bool Resource::Private::cacheEnabled = false;
QMutex Resource::Private::cacheMutex;

QHash<qint64, Resource > Resource::Private::idCache;

QHash<QString, Resource > Resource::Private::nameCache;



void Resource::Private::addToCache( const Resource & entry )
{
  Q_ASSERT( cacheEnabled );
  Q_UNUSED( entry ); 
  cacheMutex.lock();
  
  idCache.insert( entry.id(), entry );
  
  nameCache.insert( entry.name(), entry );
  
  cacheMutex.unlock();
}


// constructor
Resource::Resource() : Entity(),
  d( new Private )
{
}

Resource::Resource(
  const QString &name, bool isVirtual
) :
  Entity(),
  d( new Private )
{

  d->name = name;
  d->name_changed = true;

  d->isVirtual = isVirtual;
  d->isVirtual_changed = true;

}

Resource::Resource(
  qint64 id, const QString &name, bool isVirtual
) :
  Entity( id ),
  d( new Private )
{

  d->name = name;
  d->name_changed = true;

  d->isVirtual = isVirtual;
  d->isVirtual_changed = true;

}
Resource::Resource( const Resource & other )
  : Entity( other ), d( other.d )
{
}

// destructor
Resource::~Resource() {}

// assignment operator
Resource& Resource::operator=( const Resource & other )
{
  if ( this != &other ) {
    d = other.d;
    setId( other.id() );
  }
  return *this;
}

// comparisson operator
bool Resource::operator==( const Resource & other ) const
{
  return id() == other.id();
}

// accessor methods
QString Resource::name() const
{
  return d->name;
}

void Resource::
setName( const QString &name )

{
  d->name = name;
  d->name_changed = true;
}

bool Resource::isVirtual() const
{
  return d->isVirtual;
}

void Resource::
setIsVirtual( bool isVirtual )

{
  d->isVirtual = isVirtual;
  d->isVirtual_changed = true;
}



// SQL table information
QString Resource::tableName()
{
  return QLatin1String( "ResourceTable" );
}

QStringList Resource::columnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "id" ) );
  
  rv.append( QLatin1String( "name" ) );
  
  rv.append( QLatin1String( "isVirtual" ) );
  
  return rv;
}

QStringList Resource::fullColumnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "ResourceTable.id" ) );
  
  rv.append( QLatin1String( "ResourceTable.name" ) );
  
  rv.append( QLatin1String( "ResourceTable.isVirtual" ) );
  
  return rv;
}


QString Resource::idColumn()
{
  return QLatin1String( "id" );
}

QString Resource::idFullColumnName()
{
  return tableName() + QLatin1String( ".id" );
}

QString Resource::nameColumn()
{
  return QLatin1String( "name" );
}

QString Resource::nameFullColumnName()
{
  return tableName() + QLatin1String( ".name" );
}

QString Resource::isVirtualColumn()
{
  return QLatin1String( "isVirtual" );
}

QString Resource::isVirtualFullColumnName()
{
  return tableName() + QLatin1String( ".isVirtual" );
}



// count records
int Resource::count( const QString &column, const QVariant &value )
{
  return Entity::count<Resource>( column, value );
}

// check existence

bool Resource::exists( qint64 id )
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::idCache.contains( id ) ) {
      Private::cacheMutex.unlock();
      return true;
    }
    Private::cacheMutex.unlock();
  }
  return count( idColumn(), id ) > 0;
}

bool Resource::exists( const QString &name )
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::nameCache.contains( name ) ) {
      Private::cacheMutex.unlock();
      return true;
    }
    Private::cacheMutex.unlock();
  }
  return count( nameColumn(), name ) > 0;
}



// result extraction
QVector< Resource > Resource::extractResult( QSqlQuery & query )
{
  QVector<Resource> rv;
  while ( query.next() ) {
    rv.append( Resource(
      
        (query.isNull(0)) ?
          qint64() :
          
          query.value( 0 ).value<qint64>()
            ,
        (query.isNull(1)) ?
          QString() :
          
          Utils::variantToString( query.value( 1 ) )
            ,
        (query.isNull(2)) ?
          bool() :
          
          query.value( 2 ).value<bool>()
            
    ) );
  }
  return rv;
}

// data retrieval
Resource Resource::retrieveById( qint64 id )
{
  
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::idCache.contains( id ) ) {
      const Resource tmp = Private::idCache.value( id );
      Private::cacheMutex.unlock();
      return tmp;
    }
    Private::cacheMutex.unlock();
  }
  
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return Resource();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  qb.addValueCondition( QLatin1String("id"), Query::Equals, id );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of record with id"
      << id << "from table" << tableName()
      << qb.query().lastError().text();
    return Resource();
  }
  if ( !qb.query().next() ) {
    return Resource();
  }

  Resource rv(
  
    (qb.query().isNull(0)) ?
      qint64() :
      
      qb.query().value( 0 ).value<qint64>()
        ,
    (qb.query().isNull(1)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 1 ) )
        ,
    (qb.query().isNull(2)) ?
      bool() :
      
      qb.query().value( 2 ).value<bool>()
        
  );
  if ( Private::cacheEnabled ) {
    Private::addToCache( rv );
  }
  return rv;

}

Resource Resource::retrieveByName( const QString &name )
{
  
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::nameCache.contains( name ) ) {
      const Resource tmp = Private::nameCache.value( name );
      Private::cacheMutex.unlock();
      return tmp;
    }
    Private::cacheMutex.unlock();
  }
  
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return Resource();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  qb.addValueCondition( QLatin1String("name"), Query::Equals, name );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of record with name"
      << name << "from table" << tableName()
      << qb.query().lastError().text();
    return Resource();
  }
  if ( !qb.query().next() ) {
    return Resource();
  }

  Resource rv(
  
    (qb.query().isNull(0)) ?
      qint64() :
      
      qb.query().value( 0 ).value<qint64>()
        ,
    (qb.query().isNull(1)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 1 ) )
        ,
    (qb.query().isNull(2)) ?
      bool() :
      
      qb.query().value( 2 ).value<bool>()
        
  );
  if ( Private::cacheEnabled ) {
    Private::addToCache( rv );
  }
  return rv;

}


QVector<Resource> Resource::retrieveAll()
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<Resource>();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of all records from table" << tableName()
      << qb.query().lastError().text() << qb.query().lastQuery();
    return QVector<Resource>();
  }
  return extractResult( qb.query() );
}

QVector<Resource> Resource::retrieveFiltered( const QString &key, const QVariant &value )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<Resource>();

  SelectQueryBuilder<Resource> qb;
  if ( value.isNull() )
    qb.addValueCondition( key, Query::Is, QVariant() );
  else
    qb.addValueCondition( key, Query::Equals, value );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of records from table" << tableName()
      << "filtered by" << key << "=" << value
      << qb.query().lastError().text();
    return QVector<Resource>();
  }
  return qb.result();
}

// data retrieval for referenced tables


// data retrieval for inverse referenced tables

QVector<Collection> Resource::collections() const
{
  return Collection::retrieveFiltered( Collection::resourceIdColumn(), id() );
}


#ifndef QT_NO_DEBUG_STREAM
// debug stream operator
QDebug & operator<<( QDebug& d, const Resource& entity )
{
  d << "[Resource: "
  
    << "id = " << entity.id()
    << ", "
    << "name = " << entity.name()
    << ", "
    << "isVirtual = " << entity.isVirtual()
    
    << "]";
  return d;
}
#endif

// inserting new data
bool Resource::insert( qint64* insertId )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Insert );
  
    if ( d->name_changed )
      qb.setColumnValue( nameColumn(), this->name() );
    
    if ( d->isVirtual_changed )
      qb.setColumnValue( isVirtualColumn(), this->isVirtual() );
    

  if ( !qb.exec() ) {
    akDebug() << "Error during insertion into table" << tableName()
      << qb.query().lastError().text();
    return false;
  }

  setId( qb.insertId() );
  if ( insertId )
    *insertId = id();
  return true;
}

bool Resource::hasPendingChanges() const
{
  return false
  
    || d->name_changed
  
    || d->isVirtual_changed
  ;
}

// update existing data
bool Resource::update()
{
  invalidateCache();
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Update );

  
    if ( d->name_changed ) {
      
      qb.setColumnValue( nameColumn(), this->name() );
    }
  
    if ( d->isVirtual_changed ) {
      
      qb.setColumnValue( isVirtualColumn(), this->isVirtual() );
    }
  
  qb.addValueCondition( QLatin1String("id"), Query::Equals, id() );
  

  if ( !qb.exec() ) {
    akDebug() << "Error during updating record with id" << id()
             << " in table" << tableName() << qb.query().lastError().text();
    return false;
  }
  return true;
}

// delete records
bool Resource::remove( const QString &column, const QVariant &value )
{
  invalidateCompleteCache();
  return Entity::remove<Resource>( column, value );
}


bool Resource::remove()
{
  invalidateCache();
  return Entity::remove<Resource>( idColumn(), id() );
}

bool Resource::remove( qint64 id )
{
  return remove( idColumn(), id );
}


// cache stuff
void Resource::invalidateCache() const
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::idCache.remove( id() );
    
    Private::nameCache.remove( name() );
    
    Private::cacheMutex.unlock();
  }
}

void Resource::invalidateCompleteCache()
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::idCache.clear();
    
    Private::nameCache.clear();
    
    Private::cacheMutex.unlock();
  }
}

void Resource::enableCache( bool enable )
{
  Private::cacheEnabled = enable;
}



// private class
class Collection::Private : public QSharedData
{
  public:
    Private() : QSharedData()
    
      , parentId( 0 )
    
      , resourceId( 0 )
    
      , remoteId()
    
      , remoteRevision()
    
      , name()
    
      , cachePolicyLocalParts()
    
      , queryString()
    
      , queryAttributes()
    
      , queryCollections()
    
      , cachePolicyCheckInterval( -1 )
    
      , cachePolicyCacheTimeout( -1 )
    
      , enabled( true )
    
      , referenced( false )
    
      , cachePolicyInherit( true )
    
      , cachePolicySyncOnDemand( false )
    
      , isVirtual( false )
    
      , syncPref( Tristate::Undefined )
    
      , displayPref( Tristate::Undefined )
    
      , indexPref( Tristate::Undefined )
    
      , remoteId_changed( false )
    
      , remoteRevision_changed( false )
    
      , name_changed( false )
    
      , parentId_changed( false )
    
      , resourceId_changed( false )
    
      , enabled_changed( false )
    
      , syncPref_changed( false )
    
      , displayPref_changed( false )
    
      , indexPref_changed( false )
    
      , referenced_changed( false )
    
      , cachePolicyInherit_changed( false )
    
      , cachePolicyCheckInterval_changed( false )
    
      , cachePolicyCacheTimeout_changed( false )
    
      , cachePolicySyncOnDemand_changed( false )
    
      , cachePolicyLocalParts_changed( false )
    
      , queryString_changed( false )
    
      , queryAttributes_changed( false )
    
      , queryCollections_changed( false )
    
      , isVirtual_changed( false )
    
    {}

    
    qint64 parentId;
    
    qint64 resourceId;
    
    QString remoteId;
    
    QString remoteRevision;
    
    QString name;
    
    QString cachePolicyLocalParts;
    
    QString queryString;
    
    QString queryAttributes;
    
    QString queryCollections;
    
    int cachePolicyCheckInterval;
    
    int cachePolicyCacheTimeout;
    
    bool enabled : 1;
    
    bool referenced : 1;
    
    bool cachePolicyInherit : 1;
    
    bool cachePolicySyncOnDemand : 1;
    
    bool isVirtual : 1;
    
    Tristate syncPref;
    
    Tristate displayPref;
    
    Tristate indexPref;
    
    bool remoteId_changed : 1;
    
    bool remoteRevision_changed : 1;
    
    bool name_changed : 1;
    
    bool parentId_changed : 1;
    
    bool resourceId_changed : 1;
    
    bool enabled_changed : 1;
    
    bool syncPref_changed : 1;
    
    bool displayPref_changed : 1;
    
    bool indexPref_changed : 1;
    
    bool referenced_changed : 1;
    
    bool cachePolicyInherit_changed : 1;
    
    bool cachePolicyCheckInterval_changed : 1;
    
    bool cachePolicyCacheTimeout_changed : 1;
    
    bool cachePolicySyncOnDemand_changed : 1;
    
    bool cachePolicyLocalParts_changed : 1;
    
    bool queryString_changed : 1;
    
    bool queryAttributes_changed : 1;
    
    bool queryCollections_changed : 1;
    
    bool isVirtual_changed : 1;
    

    static void addToCache( const Collection & entry );

    // cache
    static bool cacheEnabled;
    static QMutex cacheMutex;
    
    static QHash<qint64, Collection > idCache;
    
    static QHash<QString, Collection > nameCache;
    
};


// static members
bool Collection::Private::cacheEnabled = false;
QMutex Collection::Private::cacheMutex;

QHash<qint64, Collection > Collection::Private::idCache;

QHash<QString, Collection > Collection::Private::nameCache;



void Collection::Private::addToCache( const Collection & entry )
{
  Q_ASSERT( cacheEnabled );
  Q_UNUSED( entry ); 
  cacheMutex.lock();
  
  idCache.insert( entry.id(), entry );
  
  nameCache.insert( entry.name(), entry );
  
  cacheMutex.unlock();
}


// constructor
Collection::Collection() : Entity(),
  d( new Private )
{
}

Collection::Collection(
  const QString &remoteId, const QString &remoteRevision, const QString &name, qint64 parentId, qint64 resourceId, bool enabled, Tristate syncPref, Tristate displayPref, Tristate indexPref, bool referenced, bool cachePolicyInherit, int cachePolicyCheckInterval, int cachePolicyCacheTimeout, bool cachePolicySyncOnDemand, const QString &cachePolicyLocalParts, const QString &queryString, const QString &queryAttributes, const QString &queryCollections, bool isVirtual
) :
  Entity(),
  d( new Private )
{

  d->remoteId = remoteId;
  d->remoteId_changed = true;

  d->remoteRevision = remoteRevision;
  d->remoteRevision_changed = true;

  d->name = name;
  d->name_changed = true;

  d->parentId = parentId;
  d->parentId_changed = true;

  d->resourceId = resourceId;
  d->resourceId_changed = true;

  d->enabled = enabled;
  d->enabled_changed = true;

  d->syncPref = syncPref;
  d->syncPref_changed = true;

  d->displayPref = displayPref;
  d->displayPref_changed = true;

  d->indexPref = indexPref;
  d->indexPref_changed = true;

  d->referenced = referenced;
  d->referenced_changed = true;

  d->cachePolicyInherit = cachePolicyInherit;
  d->cachePolicyInherit_changed = true;

  d->cachePolicyCheckInterval = cachePolicyCheckInterval;
  d->cachePolicyCheckInterval_changed = true;

  d->cachePolicyCacheTimeout = cachePolicyCacheTimeout;
  d->cachePolicyCacheTimeout_changed = true;

  d->cachePolicySyncOnDemand = cachePolicySyncOnDemand;
  d->cachePolicySyncOnDemand_changed = true;

  d->cachePolicyLocalParts = cachePolicyLocalParts;
  d->cachePolicyLocalParts_changed = true;

  d->queryString = queryString;
  d->queryString_changed = true;

  d->queryAttributes = queryAttributes;
  d->queryAttributes_changed = true;

  d->queryCollections = queryCollections;
  d->queryCollections_changed = true;

  d->isVirtual = isVirtual;
  d->isVirtual_changed = true;

}

Collection::Collection(
  qint64 id, const QString &remoteId, const QString &remoteRevision, const QString &name, qint64 parentId, qint64 resourceId, bool enabled, Tristate syncPref, Tristate displayPref, Tristate indexPref, bool referenced, bool cachePolicyInherit, int cachePolicyCheckInterval, int cachePolicyCacheTimeout, bool cachePolicySyncOnDemand, const QString &cachePolicyLocalParts, const QString &queryString, const QString &queryAttributes, const QString &queryCollections, bool isVirtual
) :
  Entity( id ),
  d( new Private )
{

  d->remoteId = remoteId;
  d->remoteId_changed = true;

  d->remoteRevision = remoteRevision;
  d->remoteRevision_changed = true;

  d->name = name;
  d->name_changed = true;

  d->parentId = parentId;
  d->parentId_changed = true;

  d->resourceId = resourceId;
  d->resourceId_changed = true;

  d->enabled = enabled;
  d->enabled_changed = true;

  d->syncPref = syncPref;
  d->syncPref_changed = true;

  d->displayPref = displayPref;
  d->displayPref_changed = true;

  d->indexPref = indexPref;
  d->indexPref_changed = true;

  d->referenced = referenced;
  d->referenced_changed = true;

  d->cachePolicyInherit = cachePolicyInherit;
  d->cachePolicyInherit_changed = true;

  d->cachePolicyCheckInterval = cachePolicyCheckInterval;
  d->cachePolicyCheckInterval_changed = true;

  d->cachePolicyCacheTimeout = cachePolicyCacheTimeout;
  d->cachePolicyCacheTimeout_changed = true;

  d->cachePolicySyncOnDemand = cachePolicySyncOnDemand;
  d->cachePolicySyncOnDemand_changed = true;

  d->cachePolicyLocalParts = cachePolicyLocalParts;
  d->cachePolicyLocalParts_changed = true;

  d->queryString = queryString;
  d->queryString_changed = true;

  d->queryAttributes = queryAttributes;
  d->queryAttributes_changed = true;

  d->queryCollections = queryCollections;
  d->queryCollections_changed = true;

  d->isVirtual = isVirtual;
  d->isVirtual_changed = true;

}
Collection::Collection( const Collection & other )
  : Entity( other ), d( other.d )
{
}

// destructor
Collection::~Collection() {}

// assignment operator
Collection& Collection::operator=( const Collection & other )
{
  if ( this != &other ) {
    d = other.d;
    setId( other.id() );
  }
  return *this;
}

// comparisson operator
bool Collection::operator==( const Collection & other ) const
{
  return id() == other.id();
}

// accessor methods
QString Collection::remoteId() const
{
  return d->remoteId;
}

void Collection::
setRemoteId( const QString &remoteId )

{
  d->remoteId = remoteId;
  d->remoteId_changed = true;
}

QString Collection::remoteRevision() const
{
  return d->remoteRevision;
}

void Collection::
setRemoteRevision( const QString &remoteRevision )

{
  d->remoteRevision = remoteRevision;
  d->remoteRevision_changed = true;
}

QString Collection::name() const
{
  return d->name;
}

void Collection::
setName( const QString &name )

{
  d->name = name;
  d->name_changed = true;
}

qint64 Collection::parentId() const
{
  return d->parentId;
}

void Collection::
setParentId( qint64 parentId )

{
  d->parentId = parentId;
  d->parentId_changed = true;
}

qint64 Collection::resourceId() const
{
  return d->resourceId;
}

void Collection::
setResourceId( qint64 resourceId )

{
  d->resourceId = resourceId;
  d->resourceId_changed = true;
}

bool Collection::enabled() const
{
  return d->enabled;
}

void Collection::
setEnabled( bool enabled )

{
  d->enabled = enabled;
  d->enabled_changed = true;
}

Tristate Collection::syncPref() const
{
  return d->syncPref;
}

void Collection::
setSyncPref( Tristate syncPref )

{
  d->syncPref = syncPref;
  d->syncPref_changed = true;
}

Tristate Collection::displayPref() const
{
  return d->displayPref;
}

void Collection::
setDisplayPref( Tristate displayPref )

{
  d->displayPref = displayPref;
  d->displayPref_changed = true;
}

Tristate Collection::indexPref() const
{
  return d->indexPref;
}

void Collection::
setIndexPref( Tristate indexPref )

{
  d->indexPref = indexPref;
  d->indexPref_changed = true;
}

bool Collection::referenced() const
{
  return d->referenced;
}

void Collection::
setReferenced( bool referenced )

{
  d->referenced = referenced;
  d->referenced_changed = true;
}

bool Collection::cachePolicyInherit() const
{
  return d->cachePolicyInherit;
}

void Collection::
setCachePolicyInherit( bool cachePolicyInherit )

{
  d->cachePolicyInherit = cachePolicyInherit;
  d->cachePolicyInherit_changed = true;
}

int Collection::cachePolicyCheckInterval() const
{
  return d->cachePolicyCheckInterval;
}

void Collection::
setCachePolicyCheckInterval( int cachePolicyCheckInterval )

{
  d->cachePolicyCheckInterval = cachePolicyCheckInterval;
  d->cachePolicyCheckInterval_changed = true;
}

int Collection::cachePolicyCacheTimeout() const
{
  return d->cachePolicyCacheTimeout;
}

void Collection::
setCachePolicyCacheTimeout( int cachePolicyCacheTimeout )

{
  d->cachePolicyCacheTimeout = cachePolicyCacheTimeout;
  d->cachePolicyCacheTimeout_changed = true;
}

bool Collection::cachePolicySyncOnDemand() const
{
  return d->cachePolicySyncOnDemand;
}

void Collection::
setCachePolicySyncOnDemand( bool cachePolicySyncOnDemand )

{
  d->cachePolicySyncOnDemand = cachePolicySyncOnDemand;
  d->cachePolicySyncOnDemand_changed = true;
}

QString Collection::cachePolicyLocalParts() const
{
  return d->cachePolicyLocalParts;
}

void Collection::
setCachePolicyLocalParts( const QString &cachePolicyLocalParts )

{
  d->cachePolicyLocalParts = cachePolicyLocalParts;
  d->cachePolicyLocalParts_changed = true;
}

QString Collection::queryString() const
{
  return d->queryString;
}

void Collection::
setQueryString( const QString &queryString )

{
  d->queryString = queryString;
  d->queryString_changed = true;
}

QString Collection::queryAttributes() const
{
  return d->queryAttributes;
}

void Collection::
setQueryAttributes( const QString &queryAttributes )

{
  d->queryAttributes = queryAttributes;
  d->queryAttributes_changed = true;
}

QString Collection::queryCollections() const
{
  return d->queryCollections;
}

void Collection::
setQueryCollections( const QString &queryCollections )

{
  d->queryCollections = queryCollections;
  d->queryCollections_changed = true;
}

bool Collection::isVirtual() const
{
  return d->isVirtual;
}

void Collection::
setIsVirtual( bool isVirtual )

{
  d->isVirtual = isVirtual;
  d->isVirtual_changed = true;
}



// SQL table information
QString Collection::tableName()
{
  return QLatin1String( "CollectionTable" );
}

QStringList Collection::columnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "id" ) );
  
  rv.append( QLatin1String( "remoteId" ) );
  
  rv.append( QLatin1String( "remoteRevision" ) );
  
  rv.append( QLatin1String( "name" ) );
  
  rv.append( QLatin1String( "parentId" ) );
  
  rv.append( QLatin1String( "resourceId" ) );
  
  rv.append( QLatin1String( "enabled" ) );
  
  rv.append( QLatin1String( "syncPref" ) );
  
  rv.append( QLatin1String( "displayPref" ) );
  
  rv.append( QLatin1String( "indexPref" ) );
  
  rv.append( QLatin1String( "referenced" ) );
  
  rv.append( QLatin1String( "cachePolicyInherit" ) );
  
  rv.append( QLatin1String( "cachePolicyCheckInterval" ) );
  
  rv.append( QLatin1String( "cachePolicyCacheTimeout" ) );
  
  rv.append( QLatin1String( "cachePolicySyncOnDemand" ) );
  
  rv.append( QLatin1String( "cachePolicyLocalParts" ) );
  
  rv.append( QLatin1String( "queryString" ) );
  
  rv.append( QLatin1String( "queryAttributes" ) );
  
  rv.append( QLatin1String( "queryCollections" ) );
  
  rv.append( QLatin1String( "isVirtual" ) );
  
  return rv;
}

QStringList Collection::fullColumnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "CollectionTable.id" ) );
  
  rv.append( QLatin1String( "CollectionTable.remoteId" ) );
  
  rv.append( QLatin1String( "CollectionTable.remoteRevision" ) );
  
  rv.append( QLatin1String( "CollectionTable.name" ) );
  
  rv.append( QLatin1String( "CollectionTable.parentId" ) );
  
  rv.append( QLatin1String( "CollectionTable.resourceId" ) );
  
  rv.append( QLatin1String( "CollectionTable.enabled" ) );
  
  rv.append( QLatin1String( "CollectionTable.syncPref" ) );
  
  rv.append( QLatin1String( "CollectionTable.displayPref" ) );
  
  rv.append( QLatin1String( "CollectionTable.indexPref" ) );
  
  rv.append( QLatin1String( "CollectionTable.referenced" ) );
  
  rv.append( QLatin1String( "CollectionTable.cachePolicyInherit" ) );
  
  rv.append( QLatin1String( "CollectionTable.cachePolicyCheckInterval" ) );
  
  rv.append( QLatin1String( "CollectionTable.cachePolicyCacheTimeout" ) );
  
  rv.append( QLatin1String( "CollectionTable.cachePolicySyncOnDemand" ) );
  
  rv.append( QLatin1String( "CollectionTable.cachePolicyLocalParts" ) );
  
  rv.append( QLatin1String( "CollectionTable.queryString" ) );
  
  rv.append( QLatin1String( "CollectionTable.queryAttributes" ) );
  
  rv.append( QLatin1String( "CollectionTable.queryCollections" ) );
  
  rv.append( QLatin1String( "CollectionTable.isVirtual" ) );
  
  return rv;
}


QString Collection::idColumn()
{
  return QLatin1String( "id" );
}

QString Collection::idFullColumnName()
{
  return tableName() + QLatin1String( ".id" );
}

QString Collection::remoteIdColumn()
{
  return QLatin1String( "remoteId" );
}

QString Collection::remoteIdFullColumnName()
{
  return tableName() + QLatin1String( ".remoteId" );
}

QString Collection::remoteRevisionColumn()
{
  return QLatin1String( "remoteRevision" );
}

QString Collection::remoteRevisionFullColumnName()
{
  return tableName() + QLatin1String( ".remoteRevision" );
}

QString Collection::nameColumn()
{
  return QLatin1String( "name" );
}

QString Collection::nameFullColumnName()
{
  return tableName() + QLatin1String( ".name" );
}

QString Collection::parentIdColumn()
{
  return QLatin1String( "parentId" );
}

QString Collection::parentIdFullColumnName()
{
  return tableName() + QLatin1String( ".parentId" );
}

QString Collection::resourceIdColumn()
{
  return QLatin1String( "resourceId" );
}

QString Collection::resourceIdFullColumnName()
{
  return tableName() + QLatin1String( ".resourceId" );
}

QString Collection::enabledColumn()
{
  return QLatin1String( "enabled" );
}

QString Collection::enabledFullColumnName()
{
  return tableName() + QLatin1String( ".enabled" );
}

QString Collection::syncPrefColumn()
{
  return QLatin1String( "syncPref" );
}

QString Collection::syncPrefFullColumnName()
{
  return tableName() + QLatin1String( ".syncPref" );
}

QString Collection::displayPrefColumn()
{
  return QLatin1String( "displayPref" );
}

QString Collection::displayPrefFullColumnName()
{
  return tableName() + QLatin1String( ".displayPref" );
}

QString Collection::indexPrefColumn()
{
  return QLatin1String( "indexPref" );
}

QString Collection::indexPrefFullColumnName()
{
  return tableName() + QLatin1String( ".indexPref" );
}

QString Collection::referencedColumn()
{
  return QLatin1String( "referenced" );
}

QString Collection::referencedFullColumnName()
{
  return tableName() + QLatin1String( ".referenced" );
}

QString Collection::cachePolicyInheritColumn()
{
  return QLatin1String( "cachePolicyInherit" );
}

QString Collection::cachePolicyInheritFullColumnName()
{
  return tableName() + QLatin1String( ".cachePolicyInherit" );
}

QString Collection::cachePolicyCheckIntervalColumn()
{
  return QLatin1String( "cachePolicyCheckInterval" );
}

QString Collection::cachePolicyCheckIntervalFullColumnName()
{
  return tableName() + QLatin1String( ".cachePolicyCheckInterval" );
}

QString Collection::cachePolicyCacheTimeoutColumn()
{
  return QLatin1String( "cachePolicyCacheTimeout" );
}

QString Collection::cachePolicyCacheTimeoutFullColumnName()
{
  return tableName() + QLatin1String( ".cachePolicyCacheTimeout" );
}

QString Collection::cachePolicySyncOnDemandColumn()
{
  return QLatin1String( "cachePolicySyncOnDemand" );
}

QString Collection::cachePolicySyncOnDemandFullColumnName()
{
  return tableName() + QLatin1String( ".cachePolicySyncOnDemand" );
}

QString Collection::cachePolicyLocalPartsColumn()
{
  return QLatin1String( "cachePolicyLocalParts" );
}

QString Collection::cachePolicyLocalPartsFullColumnName()
{
  return tableName() + QLatin1String( ".cachePolicyLocalParts" );
}

QString Collection::queryStringColumn()
{
  return QLatin1String( "queryString" );
}

QString Collection::queryStringFullColumnName()
{
  return tableName() + QLatin1String( ".queryString" );
}

QString Collection::queryAttributesColumn()
{
  return QLatin1String( "queryAttributes" );
}

QString Collection::queryAttributesFullColumnName()
{
  return tableName() + QLatin1String( ".queryAttributes" );
}

QString Collection::queryCollectionsColumn()
{
  return QLatin1String( "queryCollections" );
}

QString Collection::queryCollectionsFullColumnName()
{
  return tableName() + QLatin1String( ".queryCollections" );
}

QString Collection::isVirtualColumn()
{
  return QLatin1String( "isVirtual" );
}

QString Collection::isVirtualFullColumnName()
{
  return tableName() + QLatin1String( ".isVirtual" );
}



// count records
int Collection::count( const QString &column, const QVariant &value )
{
  return Entity::count<Collection>( column, value );
}

// check existence

bool Collection::exists( qint64 id )
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::idCache.contains( id ) ) {
      Private::cacheMutex.unlock();
      return true;
    }
    Private::cacheMutex.unlock();
  }
  return count( idColumn(), id ) > 0;
}

bool Collection::exists( const QString &name )
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::nameCache.contains( name ) ) {
      Private::cacheMutex.unlock();
      return true;
    }
    Private::cacheMutex.unlock();
  }
  return count( nameColumn(), name ) > 0;
}



// result extraction
QVector< Collection > Collection::extractResult( QSqlQuery & query )
{
  QVector<Collection> rv;
  while ( query.next() ) {
    rv.append( Collection(
      
        (query.isNull(0)) ?
          qint64() :
          
          query.value( 0 ).value<qint64>()
            ,
        (query.isNull(1)) ?
          QString() :
          
          Utils::variantToString( query.value( 1 ) )
            ,
        (query.isNull(2)) ?
          QString() :
          
          Utils::variantToString( query.value( 2 ) )
            ,
        (query.isNull(3)) ?
          QString() :
          
          Utils::variantToString( query.value( 3 ) )
            ,
        (query.isNull(4)) ?
          qint64() :
          
          query.value( 4 ).value<qint64>()
            ,
        (query.isNull(5)) ?
          qint64() :
          
          query.value( 5 ).value<qint64>()
            ,
        (query.isNull(6)) ?
          bool() :
          
          query.value( 6 ).value<bool>()
            ,
        (query.isNull(7)) ?
          Tristate() :
          
          static_cast<Tristate>(query.value( 7 ).value<int>())
            ,
        (query.isNull(8)) ?
          Tristate() :
          
          static_cast<Tristate>(query.value( 8 ).value<int>())
            ,
        (query.isNull(9)) ?
          Tristate() :
          
          static_cast<Tristate>(query.value( 9 ).value<int>())
            ,
        (query.isNull(10)) ?
          bool() :
          
          query.value( 10 ).value<bool>()
            ,
        (query.isNull(11)) ?
          bool() :
          
          query.value( 11 ).value<bool>()
            ,
        (query.isNull(12)) ?
          int() :
          
          query.value( 12 ).value<int>()
            ,
        (query.isNull(13)) ?
          int() :
          
          query.value( 13 ).value<int>()
            ,
        (query.isNull(14)) ?
          bool() :
          
          query.value( 14 ).value<bool>()
            ,
        (query.isNull(15)) ?
          QString() :
          
          Utils::variantToString( query.value( 15 ) )
            ,
        (query.isNull(16)) ?
          QString() :
          
          Utils::variantToString( query.value( 16 ) )
            ,
        (query.isNull(17)) ?
          QString() :
          
          Utils::variantToString( query.value( 17 ) )
            ,
        (query.isNull(18)) ?
          QString() :
          
          Utils::variantToString( query.value( 18 ) )
            ,
        (query.isNull(19)) ?
          bool() :
          
          query.value( 19 ).value<bool>()
            
    ) );
  }
  return rv;
}

// data retrieval
Collection Collection::retrieveById( qint64 id )
{
  
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::idCache.contains( id ) ) {
      const Collection tmp = Private::idCache.value( id );
      Private::cacheMutex.unlock();
      return tmp;
    }
    Private::cacheMutex.unlock();
  }
  
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return Collection();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  qb.addValueCondition( QLatin1String("id"), Query::Equals, id );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of record with id"
      << id << "from table" << tableName()
      << qb.query().lastError().text();
    return Collection();
  }
  if ( !qb.query().next() ) {
    return Collection();
  }

  Collection rv(
  
    (qb.query().isNull(0)) ?
      qint64() :
      
      qb.query().value( 0 ).value<qint64>()
        ,
    (qb.query().isNull(1)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 1 ) )
        ,
    (qb.query().isNull(2)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 2 ) )
        ,
    (qb.query().isNull(3)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 3 ) )
        ,
    (qb.query().isNull(4)) ?
      qint64() :
      
      qb.query().value( 4 ).value<qint64>()
        ,
    (qb.query().isNull(5)) ?
      qint64() :
      
      qb.query().value( 5 ).value<qint64>()
        ,
    (qb.query().isNull(6)) ?
      bool() :
      
      qb.query().value( 6 ).value<bool>()
        ,
    (qb.query().isNull(7)) ?
      Tristate() :
      
      static_cast<Tristate>(qb.query().value( 7 ).value<int>())
        ,
    (qb.query().isNull(8)) ?
      Tristate() :
      
      static_cast<Tristate>(qb.query().value( 8 ).value<int>())
        ,
    (qb.query().isNull(9)) ?
      Tristate() :
      
      static_cast<Tristate>(qb.query().value( 9 ).value<int>())
        ,
    (qb.query().isNull(10)) ?
      bool() :
      
      qb.query().value( 10 ).value<bool>()
        ,
    (qb.query().isNull(11)) ?
      bool() :
      
      qb.query().value( 11 ).value<bool>()
        ,
    (qb.query().isNull(12)) ?
      int() :
      
      qb.query().value( 12 ).value<int>()
        ,
    (qb.query().isNull(13)) ?
      int() :
      
      qb.query().value( 13 ).value<int>()
        ,
    (qb.query().isNull(14)) ?
      bool() :
      
      qb.query().value( 14 ).value<bool>()
        ,
    (qb.query().isNull(15)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 15 ) )
        ,
    (qb.query().isNull(16)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 16 ) )
        ,
    (qb.query().isNull(17)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 17 ) )
        ,
    (qb.query().isNull(18)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 18 ) )
        ,
    (qb.query().isNull(19)) ?
      bool() :
      
      qb.query().value( 19 ).value<bool>()
        
  );
  if ( Private::cacheEnabled ) {
    Private::addToCache( rv );
  }
  return rv;

}

Collection Collection::retrieveByName( const QString &name )
{
  
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::nameCache.contains( name ) ) {
      const Collection tmp = Private::nameCache.value( name );
      Private::cacheMutex.unlock();
      return tmp;
    }
    Private::cacheMutex.unlock();
  }
  
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return Collection();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  qb.addValueCondition( QLatin1String("name"), Query::Equals, name );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of record with name"
      << name << "from table" << tableName()
      << qb.query().lastError().text();
    return Collection();
  }
  if ( !qb.query().next() ) {
    return Collection();
  }

  Collection rv(
  
    (qb.query().isNull(0)) ?
      qint64() :
      
      qb.query().value( 0 ).value<qint64>()
        ,
    (qb.query().isNull(1)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 1 ) )
        ,
    (qb.query().isNull(2)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 2 ) )
        ,
    (qb.query().isNull(3)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 3 ) )
        ,
    (qb.query().isNull(4)) ?
      qint64() :
      
      qb.query().value( 4 ).value<qint64>()
        ,
    (qb.query().isNull(5)) ?
      qint64() :
      
      qb.query().value( 5 ).value<qint64>()
        ,
    (qb.query().isNull(6)) ?
      bool() :
      
      qb.query().value( 6 ).value<bool>()
        ,
    (qb.query().isNull(7)) ?
      Tristate() :
      
      static_cast<Tristate>(qb.query().value( 7 ).value<int>())
        ,
    (qb.query().isNull(8)) ?
      Tristate() :
      
      static_cast<Tristate>(qb.query().value( 8 ).value<int>())
        ,
    (qb.query().isNull(9)) ?
      Tristate() :
      
      static_cast<Tristate>(qb.query().value( 9 ).value<int>())
        ,
    (qb.query().isNull(10)) ?
      bool() :
      
      qb.query().value( 10 ).value<bool>()
        ,
    (qb.query().isNull(11)) ?
      bool() :
      
      qb.query().value( 11 ).value<bool>()
        ,
    (qb.query().isNull(12)) ?
      int() :
      
      qb.query().value( 12 ).value<int>()
        ,
    (qb.query().isNull(13)) ?
      int() :
      
      qb.query().value( 13 ).value<int>()
        ,
    (qb.query().isNull(14)) ?
      bool() :
      
      qb.query().value( 14 ).value<bool>()
        ,
    (qb.query().isNull(15)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 15 ) )
        ,
    (qb.query().isNull(16)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 16 ) )
        ,
    (qb.query().isNull(17)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 17 ) )
        ,
    (qb.query().isNull(18)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 18 ) )
        ,
    (qb.query().isNull(19)) ?
      bool() :
      
      qb.query().value( 19 ).value<bool>()
        
  );
  if ( Private::cacheEnabled ) {
    Private::addToCache( rv );
  }
  return rv;

}


QVector<Collection> Collection::retrieveAll()
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<Collection>();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of all records from table" << tableName()
      << qb.query().lastError().text() << qb.query().lastQuery();
    return QVector<Collection>();
  }
  return extractResult( qb.query() );
}

QVector<Collection> Collection::retrieveFiltered( const QString &key, const QVariant &value )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<Collection>();

  SelectQueryBuilder<Collection> qb;
  if ( value.isNull() )
    qb.addValueCondition( key, Query::Is, QVariant() );
  else
    qb.addValueCondition( key, Query::Equals, value );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of records from table" << tableName()
      << "filtered by" << key << "=" << value
      << qb.query().lastError().text();
    return QVector<Collection>();
  }
  return qb.result();
}

// data retrieval for referenced tables
Collection Collection::parent() const
{
  return Collection::retrieveById( parentId() );
}

void Collection::
    setParent
    ( const Collection &value )
{
  d->parentId = value.id();
  d->parentId_changed = true;
}
Resource Collection::resource() const
{
  return Resource::retrieveById( resourceId() );
}

void Collection::
    setResource
    ( const Resource &value )
{
  d->resourceId = value.id();
  d->resourceId_changed = true;
}


// data retrieval for inverse referenced tables

QVector<Collection> Collection::children() const
{
  return Collection::retrieveFiltered( Collection::parentIdColumn(), id() );
}

QVector<PimItem> Collection::items() const
{
  return PimItem::retrieveFiltered( PimItem::collectionIdColumn(), id() );
}

QVector<CollectionAttribute> Collection::attributes() const
{
  return CollectionAttribute::retrieveFiltered( CollectionAttribute::collectionIdColumn(), id() );
}


// data retrieval for n:m relations
QVector<MimeType> Collection::mimeTypes() const
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<MimeType>();

  QueryBuilder qb( QLatin1String("MimeTypeTable"), QueryBuilder::Select );
  
    qb.addColumn( QLatin1String("MimeTypeTable.id" ) );
  
    qb.addColumn( QLatin1String("MimeTypeTable.name" ) );
  
  qb.addJoin( QueryBuilder::InnerJoin, QLatin1String("CollectionMimeTypeRelation"),
              QLatin1String("CollectionMimeTypeRelation.MimeType_id"),
              QLatin1String("MimeTypeTable.id") );
  qb.addValueCondition( QLatin1String("CollectionMimeTypeRelation.Collection_id"), Query::Equals, id() );

  if ( !qb.exec() ) {
    akDebug() << "Error during selection of records from table CollectionMimeTypeRelation"
      << qb.query().lastError().text();
    return QVector<MimeType>();
  }

  return MimeType::extractResult( qb.query() );
}

// manipulate n:m relations
bool Collection::relatesToMimeType( const MimeType & value ) const
{
  return Entity::relatesTo<CollectionMimeTypeRelation>( id(), value.id() );
}

bool Collection::relatesToMimeType( qint64 leftId, qint64 rightId )
{
  return Entity::relatesTo<CollectionMimeTypeRelation>( leftId, rightId );
}

bool Collection::addMimeType( const MimeType & value ) const
{
  return Entity::addToRelation<CollectionMimeTypeRelation>( id(), value.id() );
}

bool Collection::addMimeType( qint64 leftId, qint64 rightId )
{
  return Entity::addToRelation<CollectionMimeTypeRelation>( leftId, rightId );
}

bool Collection::removeMimeType( const MimeType & value ) const
{
  return Entity::removeFromRelation<CollectionMimeTypeRelation>( id(), value.id() );
}

bool Collection::removeMimeType( qint64 leftId, qint64 rightId )
{
  return Entity::removeFromRelation<CollectionMimeTypeRelation>( leftId, rightId );
}

bool Collection::clearMimeTypes() const
{
  return Entity::clearRelation<CollectionMimeTypeRelation>( id() );
}

bool Collection::clearMimeTypes( qint64 id )
{
  return Entity::clearRelation<CollectionMimeTypeRelation>( id );
}



// data retrieval for n:m relations
QVector<PimItem> Collection::pimItems() const
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<PimItem>();

  QueryBuilder qb( QLatin1String("PimItemTable"), QueryBuilder::Select );
  
    qb.addColumn( QLatin1String("PimItemTable.id" ) );
  
    qb.addColumn( QLatin1String("PimItemTable.rev" ) );
  
    qb.addColumn( QLatin1String("PimItemTable.remoteId" ) );
  
    qb.addColumn( QLatin1String("PimItemTable.remoteRevision" ) );
  
    qb.addColumn( QLatin1String("PimItemTable.gid" ) );
  
    qb.addColumn( QLatin1String("PimItemTable.collectionId" ) );
  
    qb.addColumn( QLatin1String("PimItemTable.mimeTypeId" ) );
  
    qb.addColumn( QLatin1String("PimItemTable.datetime" ) );
  
    qb.addColumn( QLatin1String("PimItemTable.atime" ) );
  
    qb.addColumn( QLatin1String("PimItemTable.dirty" ) );
  
    qb.addColumn( QLatin1String("PimItemTable.size" ) );
  
  qb.addJoin( QueryBuilder::InnerJoin, QLatin1String("CollectionPimItemRelation"),
              QLatin1String("CollectionPimItemRelation.PimItem_id"),
              QLatin1String("PimItemTable.id") );
  qb.addValueCondition( QLatin1String("CollectionPimItemRelation.Collection_id"), Query::Equals, id() );

  if ( !qb.exec() ) {
    akDebug() << "Error during selection of records from table CollectionPimItemRelation"
      << qb.query().lastError().text();
    return QVector<PimItem>();
  }

  return PimItem::extractResult( qb.query() );
}

// manipulate n:m relations
bool Collection::relatesToPimItem( const PimItem & value ) const
{
  return Entity::relatesTo<CollectionPimItemRelation>( id(), value.id() );
}

bool Collection::relatesToPimItem( qint64 leftId, qint64 rightId )
{
  return Entity::relatesTo<CollectionPimItemRelation>( leftId, rightId );
}

bool Collection::addPimItem( const PimItem & value ) const
{
  return Entity::addToRelation<CollectionPimItemRelation>( id(), value.id() );
}

bool Collection::addPimItem( qint64 leftId, qint64 rightId )
{
  return Entity::addToRelation<CollectionPimItemRelation>( leftId, rightId );
}

bool Collection::removePimItem( const PimItem & value ) const
{
  return Entity::removeFromRelation<CollectionPimItemRelation>( id(), value.id() );
}

bool Collection::removePimItem( qint64 leftId, qint64 rightId )
{
  return Entity::removeFromRelation<CollectionPimItemRelation>( leftId, rightId );
}

bool Collection::clearPimItems() const
{
  return Entity::clearRelation<CollectionPimItemRelation>( id() );
}

bool Collection::clearPimItems( qint64 id )
{
  return Entity::clearRelation<CollectionPimItemRelation>( id );
}



#ifndef QT_NO_DEBUG_STREAM
// debug stream operator
QDebug & operator<<( QDebug& d, const Collection& entity )
{
  d << "[Collection: "
  
    << "id = " << entity.id()
    << ", "
    << "remoteId = " << entity.remoteId()
    << ", "
    << "remoteRevision = " << entity.remoteRevision()
    << ", "
    << "name = " << entity.name()
    << ", "
    << "parentId = " << entity.parentId()
    << ", "
    << "resourceId = " << entity.resourceId()
    << ", "
    << "enabled = " << entity.enabled()
    << ", "
    << "syncPref = " << entity.syncPref()
    << ", "
    << "displayPref = " << entity.displayPref()
    << ", "
    << "indexPref = " << entity.indexPref()
    << ", "
    << "referenced = " << entity.referenced()
    << ", "
    << "cachePolicyInherit = " << entity.cachePolicyInherit()
    << ", "
    << "cachePolicyCheckInterval = " << entity.cachePolicyCheckInterval()
    << ", "
    << "cachePolicyCacheTimeout = " << entity.cachePolicyCacheTimeout()
    << ", "
    << "cachePolicySyncOnDemand = " << entity.cachePolicySyncOnDemand()
    << ", "
    << "cachePolicyLocalParts = " << entity.cachePolicyLocalParts()
    << ", "
    << "queryString = " << entity.queryString()
    << ", "
    << "queryAttributes = " << entity.queryAttributes()
    << ", "
    << "queryCollections = " << entity.queryCollections()
    << ", "
    << "isVirtual = " << entity.isVirtual()
    
    << "]";
  return d;
}
#endif

// inserting new data
bool Collection::insert( qint64* insertId )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Insert );
  
    if ( d->remoteId_changed )
      qb.setColumnValue( remoteIdColumn(), this->remoteId() );
    
    if ( d->remoteRevision_changed )
      qb.setColumnValue( remoteRevisionColumn(), this->remoteRevision() );
    
    if ( d->name_changed )
      qb.setColumnValue( nameColumn(), this->name() );
    
    if ( d->parentId_changed  && d->parentId > 0 )
      qb.setColumnValue( parentIdColumn(), this->parentId() );
    
    if ( d->resourceId_changed  && d->resourceId > 0 )
      qb.setColumnValue( resourceIdColumn(), this->resourceId() );
    
    if ( d->enabled_changed )
      qb.setColumnValue( enabledColumn(), this->enabled() );
    
    if ( d->syncPref_changed )
      qb.setColumnValue( syncPrefColumn(), this->syncPref() );
    
    if ( d->displayPref_changed )
      qb.setColumnValue( displayPrefColumn(), this->displayPref() );
    
    if ( d->indexPref_changed )
      qb.setColumnValue( indexPrefColumn(), this->indexPref() );
    
    if ( d->referenced_changed )
      qb.setColumnValue( referencedColumn(), this->referenced() );
    
    if ( d->cachePolicyInherit_changed )
      qb.setColumnValue( cachePolicyInheritColumn(), this->cachePolicyInherit() );
    
    if ( d->cachePolicyCheckInterval_changed )
      qb.setColumnValue( cachePolicyCheckIntervalColumn(), this->cachePolicyCheckInterval() );
    
    if ( d->cachePolicyCacheTimeout_changed )
      qb.setColumnValue( cachePolicyCacheTimeoutColumn(), this->cachePolicyCacheTimeout() );
    
    if ( d->cachePolicySyncOnDemand_changed )
      qb.setColumnValue( cachePolicySyncOnDemandColumn(), this->cachePolicySyncOnDemand() );
    
    if ( d->cachePolicyLocalParts_changed )
      qb.setColumnValue( cachePolicyLocalPartsColumn(), this->cachePolicyLocalParts() );
    
    if ( d->queryString_changed )
      qb.setColumnValue( queryStringColumn(), this->queryString() );
    
    if ( d->queryAttributes_changed )
      qb.setColumnValue( queryAttributesColumn(), this->queryAttributes() );
    
    if ( d->queryCollections_changed )
      qb.setColumnValue( queryCollectionsColumn(), this->queryCollections() );
    
    if ( d->isVirtual_changed )
      qb.setColumnValue( isVirtualColumn(), this->isVirtual() );
    

  if ( !qb.exec() ) {
    akDebug() << "Error during insertion into table" << tableName()
      << qb.query().lastError().text();
    return false;
  }

  setId( qb.insertId() );
  if ( insertId )
    *insertId = id();
  return true;
}

bool Collection::hasPendingChanges() const
{
  return false
  
    || d->remoteId_changed
  
    || d->remoteRevision_changed
  
    || d->name_changed
  
    || d->parentId_changed
  
    || d->resourceId_changed
  
    || d->enabled_changed
  
    || d->syncPref_changed
  
    || d->displayPref_changed
  
    || d->indexPref_changed
  
    || d->referenced_changed
  
    || d->cachePolicyInherit_changed
  
    || d->cachePolicyCheckInterval_changed
  
    || d->cachePolicyCacheTimeout_changed
  
    || d->cachePolicySyncOnDemand_changed
  
    || d->cachePolicyLocalParts_changed
  
    || d->queryString_changed
  
    || d->queryAttributes_changed
  
    || d->queryCollections_changed
  
    || d->isVirtual_changed
  ;
}

// update existing data
bool Collection::update()
{
  invalidateCache();
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Update );

  
    if ( d->remoteId_changed ) {
      
      qb.setColumnValue( remoteIdColumn(), this->remoteId() );
    }
  
    if ( d->remoteRevision_changed ) {
      
      qb.setColumnValue( remoteRevisionColumn(), this->remoteRevision() );
    }
  
    if ( d->name_changed ) {
      
      qb.setColumnValue( nameColumn(), this->name() );
    }
  
    if ( d->parentId_changed ) {
      
      if ( d->parentId <= 0 )
        qb.setColumnValue( parentIdColumn(), QVariant() );
      else
      
      qb.setColumnValue( parentIdColumn(), this->parentId() );
    }
  
    if ( d->resourceId_changed ) {
      
      if ( d->resourceId <= 0 )
        qb.setColumnValue( resourceIdColumn(), QVariant() );
      else
      
      qb.setColumnValue( resourceIdColumn(), this->resourceId() );
    }
  
    if ( d->enabled_changed ) {
      
      qb.setColumnValue( enabledColumn(), this->enabled() );
    }
  
    if ( d->syncPref_changed ) {
      
      qb.setColumnValue( syncPrefColumn(), this->syncPref() );
    }
  
    if ( d->displayPref_changed ) {
      
      qb.setColumnValue( displayPrefColumn(), this->displayPref() );
    }
  
    if ( d->indexPref_changed ) {
      
      qb.setColumnValue( indexPrefColumn(), this->indexPref() );
    }
  
    if ( d->referenced_changed ) {
      
      qb.setColumnValue( referencedColumn(), this->referenced() );
    }
  
    if ( d->cachePolicyInherit_changed ) {
      
      qb.setColumnValue( cachePolicyInheritColumn(), this->cachePolicyInherit() );
    }
  
    if ( d->cachePolicyCheckInterval_changed ) {
      
      qb.setColumnValue( cachePolicyCheckIntervalColumn(), this->cachePolicyCheckInterval() );
    }
  
    if ( d->cachePolicyCacheTimeout_changed ) {
      
      qb.setColumnValue( cachePolicyCacheTimeoutColumn(), this->cachePolicyCacheTimeout() );
    }
  
    if ( d->cachePolicySyncOnDemand_changed ) {
      
      qb.setColumnValue( cachePolicySyncOnDemandColumn(), this->cachePolicySyncOnDemand() );
    }
  
    if ( d->cachePolicyLocalParts_changed ) {
      
      qb.setColumnValue( cachePolicyLocalPartsColumn(), this->cachePolicyLocalParts() );
    }
  
    if ( d->queryString_changed ) {
      
      qb.setColumnValue( queryStringColumn(), this->queryString() );
    }
  
    if ( d->queryAttributes_changed ) {
      
      qb.setColumnValue( queryAttributesColumn(), this->queryAttributes() );
    }
  
    if ( d->queryCollections_changed ) {
      
      qb.setColumnValue( queryCollectionsColumn(), this->queryCollections() );
    }
  
    if ( d->isVirtual_changed ) {
      
      qb.setColumnValue( isVirtualColumn(), this->isVirtual() );
    }
  
  qb.addValueCondition( QLatin1String("id"), Query::Equals, id() );
  

  if ( !qb.exec() ) {
    akDebug() << "Error during updating record with id" << id()
             << " in table" << tableName() << qb.query().lastError().text();
    return false;
  }
  return true;
}

// delete records
bool Collection::remove( const QString &column, const QVariant &value )
{
  invalidateCompleteCache();
  return Entity::remove<Collection>( column, value );
}


bool Collection::remove()
{
  invalidateCache();
  return Entity::remove<Collection>( idColumn(), id() );
}

bool Collection::remove( qint64 id )
{
  return remove( idColumn(), id );
}


// cache stuff
void Collection::invalidateCache() const
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::idCache.remove( id() );
    
    Private::nameCache.remove( name() );
    
    Private::cacheMutex.unlock();
  }
}

void Collection::invalidateCompleteCache()
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::idCache.clear();
    
    Private::nameCache.clear();
    
    Private::cacheMutex.unlock();
  }
}

void Collection::enableCache( bool enable )
{
  Private::cacheEnabled = enable;
}



// private class
class MimeType::Private : public QSharedData
{
  public:
    Private() : QSharedData()
    
      , name()
    
      , name_changed( false )
    
    {}

    
    QString name;
    
    bool name_changed : 1;
    

    static void addToCache( const MimeType & entry );

    // cache
    static bool cacheEnabled;
    static QMutex cacheMutex;
    
    static QHash<qint64, MimeType > idCache;
    
    static QHash<QString, MimeType > nameCache;
    
};


// static members
bool MimeType::Private::cacheEnabled = false;
QMutex MimeType::Private::cacheMutex;

QHash<qint64, MimeType > MimeType::Private::idCache;

QHash<QString, MimeType > MimeType::Private::nameCache;



void MimeType::Private::addToCache( const MimeType & entry )
{
  Q_ASSERT( cacheEnabled );
  Q_UNUSED( entry ); 
  cacheMutex.lock();
  
  idCache.insert( entry.id(), entry );
  
  nameCache.insert( entry.name(), entry );
  
  cacheMutex.unlock();
}


// constructor
MimeType::MimeType() : Entity(),
  d( new Private )
{
}

MimeType::MimeType(
  const QString &name
) :
  Entity(),
  d( new Private )
{

  d->name = name;
  d->name_changed = true;

}

MimeType::MimeType(
  qint64 id, const QString &name
) :
  Entity( id ),
  d( new Private )
{

  d->name = name;
  d->name_changed = true;

}
MimeType::MimeType( const MimeType & other )
  : Entity( other ), d( other.d )
{
}

// destructor
MimeType::~MimeType() {}

// assignment operator
MimeType& MimeType::operator=( const MimeType & other )
{
  if ( this != &other ) {
    d = other.d;
    setId( other.id() );
  }
  return *this;
}

// comparisson operator
bool MimeType::operator==( const MimeType & other ) const
{
  return id() == other.id();
}

// accessor methods
QString MimeType::name() const
{
  return d->name;
}

void MimeType::
setName( const QString &name )

{
  d->name = name;
  d->name_changed = true;
}



// SQL table information
QString MimeType::tableName()
{
  return QLatin1String( "MimeTypeTable" );
}

QStringList MimeType::columnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "id" ) );
  
  rv.append( QLatin1String( "name" ) );
  
  return rv;
}

QStringList MimeType::fullColumnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "MimeTypeTable.id" ) );
  
  rv.append( QLatin1String( "MimeTypeTable.name" ) );
  
  return rv;
}


QString MimeType::idColumn()
{
  return QLatin1String( "id" );
}

QString MimeType::idFullColumnName()
{
  return tableName() + QLatin1String( ".id" );
}

QString MimeType::nameColumn()
{
  return QLatin1String( "name" );
}

QString MimeType::nameFullColumnName()
{
  return tableName() + QLatin1String( ".name" );
}



// count records
int MimeType::count( const QString &column, const QVariant &value )
{
  return Entity::count<MimeType>( column, value );
}

// check existence

bool MimeType::exists( qint64 id )
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::idCache.contains( id ) ) {
      Private::cacheMutex.unlock();
      return true;
    }
    Private::cacheMutex.unlock();
  }
  return count( idColumn(), id ) > 0;
}

bool MimeType::exists( const QString &name )
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::nameCache.contains( name ) ) {
      Private::cacheMutex.unlock();
      return true;
    }
    Private::cacheMutex.unlock();
  }
  return count( nameColumn(), name ) > 0;
}



// result extraction
QVector< MimeType > MimeType::extractResult( QSqlQuery & query )
{
  QVector<MimeType> rv;
  while ( query.next() ) {
    rv.append( MimeType(
      
        (query.isNull(0)) ?
          qint64() :
          
          query.value( 0 ).value<qint64>()
            ,
        (query.isNull(1)) ?
          QString() :
          
          Utils::variantToString( query.value( 1 ) )
            
    ) );
  }
  return rv;
}

// data retrieval
MimeType MimeType::retrieveById( qint64 id )
{
  
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::idCache.contains( id ) ) {
      const MimeType tmp = Private::idCache.value( id );
      Private::cacheMutex.unlock();
      return tmp;
    }
    Private::cacheMutex.unlock();
  }
  
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return MimeType();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  qb.addValueCondition( QLatin1String("id"), Query::Equals, id );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of record with id"
      << id << "from table" << tableName()
      << qb.query().lastError().text();
    return MimeType();
  }
  if ( !qb.query().next() ) {
    return MimeType();
  }

  MimeType rv(
  
    (qb.query().isNull(0)) ?
      qint64() :
      
      qb.query().value( 0 ).value<qint64>()
        ,
    (qb.query().isNull(1)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 1 ) )
        
  );
  if ( Private::cacheEnabled ) {
    Private::addToCache( rv );
  }
  return rv;

}

MimeType MimeType::retrieveByName( const QString &name )
{
  
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::nameCache.contains( name ) ) {
      const MimeType tmp = Private::nameCache.value( name );
      Private::cacheMutex.unlock();
      return tmp;
    }
    Private::cacheMutex.unlock();
  }
  
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return MimeType();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  qb.addValueCondition( QLatin1String("name"), Query::Equals, name );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of record with name"
      << name << "from table" << tableName()
      << qb.query().lastError().text();
    return MimeType();
  }
  if ( !qb.query().next() ) {
    return MimeType();
  }

  MimeType rv(
  
    (qb.query().isNull(0)) ?
      qint64() :
      
      qb.query().value( 0 ).value<qint64>()
        ,
    (qb.query().isNull(1)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 1 ) )
        
  );
  if ( Private::cacheEnabled ) {
    Private::addToCache( rv );
  }
  return rv;

}


QVector<MimeType> MimeType::retrieveAll()
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<MimeType>();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of all records from table" << tableName()
      << qb.query().lastError().text() << qb.query().lastQuery();
    return QVector<MimeType>();
  }
  return extractResult( qb.query() );
}

QVector<MimeType> MimeType::retrieveFiltered( const QString &key, const QVariant &value )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<MimeType>();

  SelectQueryBuilder<MimeType> qb;
  if ( value.isNull() )
    qb.addValueCondition( key, Query::Is, QVariant() );
  else
    qb.addValueCondition( key, Query::Equals, value );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of records from table" << tableName()
      << "filtered by" << key << "=" << value
      << qb.query().lastError().text();
    return QVector<MimeType>();
  }
  return qb.result();
}

// data retrieval for referenced tables


// data retrieval for inverse referenced tables


#ifndef QT_NO_DEBUG_STREAM
// debug stream operator
QDebug & operator<<( QDebug& d, const MimeType& entity )
{
  d << "[MimeType: "
  
    << "id = " << entity.id()
    << ", "
    << "name = " << entity.name()
    
    << "]";
  return d;
}
#endif

// inserting new data
bool MimeType::insert( qint64* insertId )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Insert );
  
    if ( d->name_changed )
      qb.setColumnValue( nameColumn(), this->name() );
    

  if ( !qb.exec() ) {
    akDebug() << "Error during insertion into table" << tableName()
      << qb.query().lastError().text();
    return false;
  }

  setId( qb.insertId() );
  if ( insertId )
    *insertId = id();
  return true;
}

bool MimeType::hasPendingChanges() const
{
  return false
  
    || d->name_changed
  ;
}

// update existing data
bool MimeType::update()
{
  invalidateCache();
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Update );

  
    if ( d->name_changed ) {
      
      qb.setColumnValue( nameColumn(), this->name() );
    }
  
  qb.addValueCondition( QLatin1String("id"), Query::Equals, id() );
  

  if ( !qb.exec() ) {
    akDebug() << "Error during updating record with id" << id()
             << " in table" << tableName() << qb.query().lastError().text();
    return false;
  }
  return true;
}

// delete records
bool MimeType::remove( const QString &column, const QVariant &value )
{
  invalidateCompleteCache();
  return Entity::remove<MimeType>( column, value );
}


bool MimeType::remove()
{
  invalidateCache();
  return Entity::remove<MimeType>( idColumn(), id() );
}

bool MimeType::remove( qint64 id )
{
  return remove( idColumn(), id );
}


// cache stuff
void MimeType::invalidateCache() const
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::idCache.remove( id() );
    
    Private::nameCache.remove( name() );
    
    Private::cacheMutex.unlock();
  }
}

void MimeType::invalidateCompleteCache()
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::idCache.clear();
    
    Private::nameCache.clear();
    
    Private::cacheMutex.unlock();
  }
}

void MimeType::enableCache( bool enable )
{
  Private::cacheEnabled = enable;
}



// private class
class PimItem::Private : public QSharedData
{
  public:
    Private() : QSharedData()
    
      , collectionId( 0 )
    
      , mimeTypeId( 0 )
    
      , size( 0 )
    
      , remoteId()
    
      , remoteRevision()
    
      , gid()
    
    // on non-wince, QDateTime is one int
    
      , datetime()
    
      , atime()
    
      , rev( 0 )
    
      , dirty( false )
    
      , rev_changed( false )
    
      , remoteId_changed( false )
    
      , remoteRevision_changed( false )
    
      , gid_changed( false )
    
      , collectionId_changed( false )
    
      , mimeTypeId_changed( false )
    
      , datetime_changed( false )
    
      , atime_changed( false )
    
      , dirty_changed( false )
    
      , size_changed( false )
    
    {}

    
    qint64 collectionId;
    
    qint64 mimeTypeId;
    
    qint64 size;
    
    QString remoteId;
    
    QString remoteRevision;
    
    QString gid;
    
    // on non-wince, QDateTime is one int
    
    QDateTime datetime;
    
    QDateTime atime;
    
    int rev;
    
    bool dirty : 1;
    
    bool rev_changed : 1;
    
    bool remoteId_changed : 1;
    
    bool remoteRevision_changed : 1;
    
    bool gid_changed : 1;
    
    bool collectionId_changed : 1;
    
    bool mimeTypeId_changed : 1;
    
    bool datetime_changed : 1;
    
    bool atime_changed : 1;
    
    bool dirty_changed : 1;
    
    bool size_changed : 1;
    

    static void addToCache( const PimItem & entry );

    // cache
    static bool cacheEnabled;
    static QMutex cacheMutex;
    
    static QHash<qint64, PimItem > idCache;
    
};


// static members
bool PimItem::Private::cacheEnabled = false;
QMutex PimItem::Private::cacheMutex;

QHash<qint64, PimItem > PimItem::Private::idCache;



void PimItem::Private::addToCache( const PimItem & entry )
{
  Q_ASSERT( cacheEnabled );
  Q_UNUSED( entry ); 
  cacheMutex.lock();
  
  idCache.insert( entry.id(), entry );
  
  cacheMutex.unlock();
}


// constructor
PimItem::PimItem() : Entity(),
  d( new Private )
{
}

PimItem::PimItem(
  int rev, const QString &remoteId, const QString &remoteRevision, const QString &gid, qint64 collectionId, qint64 mimeTypeId, const QDateTime &datetime, const QDateTime &atime, bool dirty, qint64 size
) :
  Entity(),
  d( new Private )
{

  d->rev = rev;
  d->rev_changed = true;

  d->remoteId = remoteId;
  d->remoteId_changed = true;

  d->remoteRevision = remoteRevision;
  d->remoteRevision_changed = true;

  d->gid = gid;
  d->gid_changed = true;

  d->collectionId = collectionId;
  d->collectionId_changed = true;

  d->mimeTypeId = mimeTypeId;
  d->mimeTypeId_changed = true;

  d->datetime = datetime;
  d->datetime_changed = true;

  d->atime = atime;
  d->atime_changed = true;

  d->dirty = dirty;
  d->dirty_changed = true;

  d->size = size;
  d->size_changed = true;

}

PimItem::PimItem(
  qint64 id, int rev, const QString &remoteId, const QString &remoteRevision, const QString &gid, qint64 collectionId, qint64 mimeTypeId, const QDateTime &datetime, const QDateTime &atime, bool dirty, qint64 size
) :
  Entity( id ),
  d( new Private )
{

  d->rev = rev;
  d->rev_changed = true;

  d->remoteId = remoteId;
  d->remoteId_changed = true;

  d->remoteRevision = remoteRevision;
  d->remoteRevision_changed = true;

  d->gid = gid;
  d->gid_changed = true;

  d->collectionId = collectionId;
  d->collectionId_changed = true;

  d->mimeTypeId = mimeTypeId;
  d->mimeTypeId_changed = true;

  d->datetime = datetime;
  d->datetime_changed = true;

  d->atime = atime;
  d->atime_changed = true;

  d->dirty = dirty;
  d->dirty_changed = true;

  d->size = size;
  d->size_changed = true;

}
PimItem::PimItem( const PimItem & other )
  : Entity( other ), d( other.d )
{
}

// destructor
PimItem::~PimItem() {}

// assignment operator
PimItem& PimItem::operator=( const PimItem & other )
{
  if ( this != &other ) {
    d = other.d;
    setId( other.id() );
  }
  return *this;
}

// comparisson operator
bool PimItem::operator==( const PimItem & other ) const
{
  return id() == other.id();
}

// accessor methods
int PimItem::rev() const
{
  return d->rev;
}

void PimItem::
setRev( int rev )

{
  d->rev = rev;
  d->rev_changed = true;
}

QString PimItem::remoteId() const
{
  return d->remoteId;
}

void PimItem::
setRemoteId( const QString &remoteId )

{
  d->remoteId = remoteId;
  d->remoteId_changed = true;
}

QString PimItem::remoteRevision() const
{
  return d->remoteRevision;
}

void PimItem::
setRemoteRevision( const QString &remoteRevision )

{
  d->remoteRevision = remoteRevision;
  d->remoteRevision_changed = true;
}

QString PimItem::gid() const
{
  return d->gid;
}

void PimItem::
setGid( const QString &gid )

{
  d->gid = gid;
  d->gid_changed = true;
}

qint64 PimItem::collectionId() const
{
  return d->collectionId;
}

void PimItem::
setCollectionId( qint64 collectionId )

{
  d->collectionId = collectionId;
  d->collectionId_changed = true;
}

qint64 PimItem::mimeTypeId() const
{
  return d->mimeTypeId;
}

void PimItem::
setMimeTypeId( qint64 mimeTypeId )

{
  d->mimeTypeId = mimeTypeId;
  d->mimeTypeId_changed = true;
}

QDateTime PimItem::datetime() const
{
  return d->datetime;
}

void PimItem::
setDatetime( const QDateTime &datetime )

{
  d->datetime = datetime;
  d->datetime_changed = true;
}

QDateTime PimItem::atime() const
{
  return d->atime;
}

void PimItem::
setAtime( const QDateTime &atime )

{
  d->atime = atime;
  d->atime_changed = true;
}

bool PimItem::dirty() const
{
  return d->dirty;
}

void PimItem::
setDirty( bool dirty )

{
  d->dirty = dirty;
  d->dirty_changed = true;
}

qint64 PimItem::size() const
{
  return d->size;
}

void PimItem::
setSize( qint64 size )

{
  d->size = size;
  d->size_changed = true;
}



// SQL table information
QString PimItem::tableName()
{
  return QLatin1String( "PimItemTable" );
}

QStringList PimItem::columnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "id" ) );
  
  rv.append( QLatin1String( "rev" ) );
  
  rv.append( QLatin1String( "remoteId" ) );
  
  rv.append( QLatin1String( "remoteRevision" ) );
  
  rv.append( QLatin1String( "gid" ) );
  
  rv.append( QLatin1String( "collectionId" ) );
  
  rv.append( QLatin1String( "mimeTypeId" ) );
  
  rv.append( QLatin1String( "datetime" ) );
  
  rv.append( QLatin1String( "atime" ) );
  
  rv.append( QLatin1String( "dirty" ) );
  
  rv.append( QLatin1String( "size" ) );
  
  return rv;
}

QStringList PimItem::fullColumnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "PimItemTable.id" ) );
  
  rv.append( QLatin1String( "PimItemTable.rev" ) );
  
  rv.append( QLatin1String( "PimItemTable.remoteId" ) );
  
  rv.append( QLatin1String( "PimItemTable.remoteRevision" ) );
  
  rv.append( QLatin1String( "PimItemTable.gid" ) );
  
  rv.append( QLatin1String( "PimItemTable.collectionId" ) );
  
  rv.append( QLatin1String( "PimItemTable.mimeTypeId" ) );
  
  rv.append( QLatin1String( "PimItemTable.datetime" ) );
  
  rv.append( QLatin1String( "PimItemTable.atime" ) );
  
  rv.append( QLatin1String( "PimItemTable.dirty" ) );
  
  rv.append( QLatin1String( "PimItemTable.size" ) );
  
  return rv;
}


QString PimItem::idColumn()
{
  return QLatin1String( "id" );
}

QString PimItem::idFullColumnName()
{
  return tableName() + QLatin1String( ".id" );
}

QString PimItem::revColumn()
{
  return QLatin1String( "rev" );
}

QString PimItem::revFullColumnName()
{
  return tableName() + QLatin1String( ".rev" );
}

QString PimItem::remoteIdColumn()
{
  return QLatin1String( "remoteId" );
}

QString PimItem::remoteIdFullColumnName()
{
  return tableName() + QLatin1String( ".remoteId" );
}

QString PimItem::remoteRevisionColumn()
{
  return QLatin1String( "remoteRevision" );
}

QString PimItem::remoteRevisionFullColumnName()
{
  return tableName() + QLatin1String( ".remoteRevision" );
}

QString PimItem::gidColumn()
{
  return QLatin1String( "gid" );
}

QString PimItem::gidFullColumnName()
{
  return tableName() + QLatin1String( ".gid" );
}

QString PimItem::collectionIdColumn()
{
  return QLatin1String( "collectionId" );
}

QString PimItem::collectionIdFullColumnName()
{
  return tableName() + QLatin1String( ".collectionId" );
}

QString PimItem::mimeTypeIdColumn()
{
  return QLatin1String( "mimeTypeId" );
}

QString PimItem::mimeTypeIdFullColumnName()
{
  return tableName() + QLatin1String( ".mimeTypeId" );
}

QString PimItem::datetimeColumn()
{
  return QLatin1String( "datetime" );
}

QString PimItem::datetimeFullColumnName()
{
  return tableName() + QLatin1String( ".datetime" );
}

QString PimItem::atimeColumn()
{
  return QLatin1String( "atime" );
}

QString PimItem::atimeFullColumnName()
{
  return tableName() + QLatin1String( ".atime" );
}

QString PimItem::dirtyColumn()
{
  return QLatin1String( "dirty" );
}

QString PimItem::dirtyFullColumnName()
{
  return tableName() + QLatin1String( ".dirty" );
}

QString PimItem::sizeColumn()
{
  return QLatin1String( "size" );
}

QString PimItem::sizeFullColumnName()
{
  return tableName() + QLatin1String( ".size" );
}



// count records
int PimItem::count( const QString &column, const QVariant &value )
{
  return Entity::count<PimItem>( column, value );
}

// check existence

bool PimItem::exists( qint64 id )
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::idCache.contains( id ) ) {
      Private::cacheMutex.unlock();
      return true;
    }
    Private::cacheMutex.unlock();
  }
  return count( idColumn(), id ) > 0;
}



// result extraction
QVector< PimItem > PimItem::extractResult( QSqlQuery & query )
{
  QVector<PimItem> rv;
  while ( query.next() ) {
    rv.append( PimItem(
      
        (query.isNull(0)) ?
          qint64() :
          
          query.value( 0 ).value<qint64>()
            ,
        (query.isNull(1)) ?
          int() :
          
          query.value( 1 ).value<int>()
            ,
        (query.isNull(2)) ?
          QString() :
          
          Utils::variantToString( query.value( 2 ) )
            ,
        (query.isNull(3)) ?
          QString() :
          
          Utils::variantToString( query.value( 3 ) )
            ,
        (query.isNull(4)) ?
          QString() :
          
          Utils::variantToString( query.value( 4 ) )
            ,
        (query.isNull(5)) ?
          qint64() :
          
          query.value( 5 ).value<qint64>()
            ,
        (query.isNull(6)) ?
          qint64() :
          
          query.value( 6 ).value<qint64>()
            ,
        (query.isNull(7)) ?
          QDateTime() :
          
          query.value( 7 ).value<QDateTime>()
            ,
        (query.isNull(8)) ?
          QDateTime() :
          
          query.value( 8 ).value<QDateTime>()
            ,
        (query.isNull(9)) ?
          bool() :
          
          query.value( 9 ).value<bool>()
            ,
        (query.isNull(10)) ?
          qint64() :
          
          query.value( 10 ).value<qint64>()
            
    ) );
  }
  return rv;
}

// data retrieval
PimItem PimItem::retrieveById( qint64 id )
{
  
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::idCache.contains( id ) ) {
      const PimItem tmp = Private::idCache.value( id );
      Private::cacheMutex.unlock();
      return tmp;
    }
    Private::cacheMutex.unlock();
  }
  
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return PimItem();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  qb.addValueCondition( QLatin1String("id"), Query::Equals, id );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of record with id"
      << id << "from table" << tableName()
      << qb.query().lastError().text();
    return PimItem();
  }
  if ( !qb.query().next() ) {
    return PimItem();
  }

  PimItem rv(
  
    (qb.query().isNull(0)) ?
      qint64() :
      
      qb.query().value( 0 ).value<qint64>()
        ,
    (qb.query().isNull(1)) ?
      int() :
      
      qb.query().value( 1 ).value<int>()
        ,
    (qb.query().isNull(2)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 2 ) )
        ,
    (qb.query().isNull(3)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 3 ) )
        ,
    (qb.query().isNull(4)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 4 ) )
        ,
    (qb.query().isNull(5)) ?
      qint64() :
      
      qb.query().value( 5 ).value<qint64>()
        ,
    (qb.query().isNull(6)) ?
      qint64() :
      
      qb.query().value( 6 ).value<qint64>()
        ,
    (qb.query().isNull(7)) ?
      QDateTime() :
      
      qb.query().value( 7 ).value<QDateTime>()
        ,
    (qb.query().isNull(8)) ?
      QDateTime() :
      
      qb.query().value( 8 ).value<QDateTime>()
        ,
    (qb.query().isNull(9)) ?
      bool() :
      
      qb.query().value( 9 ).value<bool>()
        ,
    (qb.query().isNull(10)) ?
      qint64() :
      
      qb.query().value( 10 ).value<qint64>()
        
  );
  if ( Private::cacheEnabled ) {
    Private::addToCache( rv );
  }
  return rv;

}



QVector<PimItem> PimItem::retrieveAll()
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<PimItem>();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of all records from table" << tableName()
      << qb.query().lastError().text() << qb.query().lastQuery();
    return QVector<PimItem>();
  }
  return extractResult( qb.query() );
}

QVector<PimItem> PimItem::retrieveFiltered( const QString &key, const QVariant &value )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<PimItem>();

  SelectQueryBuilder<PimItem> qb;
  if ( value.isNull() )
    qb.addValueCondition( key, Query::Is, QVariant() );
  else
    qb.addValueCondition( key, Query::Equals, value );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of records from table" << tableName()
      << "filtered by" << key << "=" << value
      << qb.query().lastError().text();
    return QVector<PimItem>();
  }
  return qb.result();
}

// data retrieval for referenced tables
Collection PimItem::collection() const
{
  return Collection::retrieveById( collectionId() );
}

void PimItem::
    setCollection
    ( const Collection &value )
{
  d->collectionId = value.id();
  d->collectionId_changed = true;
}
MimeType PimItem::mimeType() const
{
  return MimeType::retrieveById( mimeTypeId() );
}

void PimItem::
    setMimeType
    ( const MimeType &value )
{
  d->mimeTypeId = value.id();
  d->mimeTypeId_changed = true;
}


// data retrieval for inverse referenced tables

QVector<Part> PimItem::parts() const
{
  return Part::retrieveFiltered( Part::pimItemIdColumn(), id() );
}


// data retrieval for n:m relations
QVector<Flag> PimItem::flags() const
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<Flag>();

  QueryBuilder qb( QLatin1String("FlagTable"), QueryBuilder::Select );
  
    qb.addColumn( QLatin1String("FlagTable.id" ) );
  
    qb.addColumn( QLatin1String("FlagTable.name" ) );
  
  qb.addJoin( QueryBuilder::InnerJoin, QLatin1String("PimItemFlagRelation"),
              QLatin1String("PimItemFlagRelation.Flag_id"),
              QLatin1String("FlagTable.id") );
  qb.addValueCondition( QLatin1String("PimItemFlagRelation.PimItem_id"), Query::Equals, id() );

  if ( !qb.exec() ) {
    akDebug() << "Error during selection of records from table PimItemFlagRelation"
      << qb.query().lastError().text();
    return QVector<Flag>();
  }

  return Flag::extractResult( qb.query() );
}

// manipulate n:m relations
bool PimItem::relatesToFlag( const Flag & value ) const
{
  return Entity::relatesTo<PimItemFlagRelation>( id(), value.id() );
}

bool PimItem::relatesToFlag( qint64 leftId, qint64 rightId )
{
  return Entity::relatesTo<PimItemFlagRelation>( leftId, rightId );
}

bool PimItem::addFlag( const Flag & value ) const
{
  return Entity::addToRelation<PimItemFlagRelation>( id(), value.id() );
}

bool PimItem::addFlag( qint64 leftId, qint64 rightId )
{
  return Entity::addToRelation<PimItemFlagRelation>( leftId, rightId );
}

bool PimItem::removeFlag( const Flag & value ) const
{
  return Entity::removeFromRelation<PimItemFlagRelation>( id(), value.id() );
}

bool PimItem::removeFlag( qint64 leftId, qint64 rightId )
{
  return Entity::removeFromRelation<PimItemFlagRelation>( leftId, rightId );
}

bool PimItem::clearFlags() const
{
  return Entity::clearRelation<PimItemFlagRelation>( id() );
}

bool PimItem::clearFlags( qint64 id )
{
  return Entity::clearRelation<PimItemFlagRelation>( id );
}



// data retrieval for n:m relations
QVector<Tag> PimItem::tags() const
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<Tag>();

  QueryBuilder qb( QLatin1String("TagTable"), QueryBuilder::Select );
  
    qb.addColumn( QLatin1String("TagTable.id" ) );
  
    qb.addColumn( QLatin1String("TagTable.gid" ) );
  
    qb.addColumn( QLatin1String("TagTable.parentId" ) );
  
    qb.addColumn( QLatin1String("TagTable.typeId" ) );
  
  qb.addJoin( QueryBuilder::InnerJoin, QLatin1String("PimItemTagRelation"),
              QLatin1String("PimItemTagRelation.Tag_id"),
              QLatin1String("TagTable.id") );
  qb.addValueCondition( QLatin1String("PimItemTagRelation.PimItem_id"), Query::Equals, id() );

  if ( !qb.exec() ) {
    akDebug() << "Error during selection of records from table PimItemTagRelation"
      << qb.query().lastError().text();
    return QVector<Tag>();
  }

  return Tag::extractResult( qb.query() );
}

// manipulate n:m relations
bool PimItem::relatesToTag( const Tag & value ) const
{
  return Entity::relatesTo<PimItemTagRelation>( id(), value.id() );
}

bool PimItem::relatesToTag( qint64 leftId, qint64 rightId )
{
  return Entity::relatesTo<PimItemTagRelation>( leftId, rightId );
}

bool PimItem::addTag( const Tag & value ) const
{
  return Entity::addToRelation<PimItemTagRelation>( id(), value.id() );
}

bool PimItem::addTag( qint64 leftId, qint64 rightId )
{
  return Entity::addToRelation<PimItemTagRelation>( leftId, rightId );
}

bool PimItem::removeTag( const Tag & value ) const
{
  return Entity::removeFromRelation<PimItemTagRelation>( id(), value.id() );
}

bool PimItem::removeTag( qint64 leftId, qint64 rightId )
{
  return Entity::removeFromRelation<PimItemTagRelation>( leftId, rightId );
}

bool PimItem::clearTags() const
{
  return Entity::clearRelation<PimItemTagRelation>( id() );
}

bool PimItem::clearTags( qint64 id )
{
  return Entity::clearRelation<PimItemTagRelation>( id );
}



#ifndef QT_NO_DEBUG_STREAM
// debug stream operator
QDebug & operator<<( QDebug& d, const PimItem& entity )
{
  d << "[PimItem: "
  
    << "id = " << entity.id()
    << ", "
    << "rev = " << entity.rev()
    << ", "
    << "remoteId = " << entity.remoteId()
    << ", "
    << "remoteRevision = " << entity.remoteRevision()
    << ", "
    << "gid = " << entity.gid()
    << ", "
    << "collectionId = " << entity.collectionId()
    << ", "
    << "mimeTypeId = " << entity.mimeTypeId()
    << ", "
    << "datetime = " << entity.datetime()
    << ", "
    << "atime = " << entity.atime()
    << ", "
    << "dirty = " << entity.dirty()
    << ", "
    << "size = " << entity.size()
    
    << "]";
  return d;
}
#endif

// inserting new data
bool PimItem::insert( qint64* insertId )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Insert );
  
    if ( d->rev_changed )
      qb.setColumnValue( revColumn(), this->rev() );
    
    if ( d->remoteId_changed )
      qb.setColumnValue( remoteIdColumn(), this->remoteId() );
    
    if ( d->remoteRevision_changed )
      qb.setColumnValue( remoteRevisionColumn(), this->remoteRevision() );
    
    if ( d->gid_changed )
      qb.setColumnValue( gidColumn(), this->gid() );
    
    if ( d->collectionId_changed  && d->collectionId > 0 )
      qb.setColumnValue( collectionIdColumn(), this->collectionId() );
    
    if ( d->mimeTypeId_changed  && d->mimeTypeId > 0 )
      qb.setColumnValue( mimeTypeIdColumn(), this->mimeTypeId() );
    
    if ( d->datetime_changed )
      qb.setColumnValue( datetimeColumn(), this->datetime() );
    
    if ( d->atime_changed )
      qb.setColumnValue( atimeColumn(), this->atime() );
    
    if ( d->dirty_changed )
      qb.setColumnValue( dirtyColumn(), this->dirty() );
    
    if ( d->size_changed )
      qb.setColumnValue( sizeColumn(), this->size() );
    

  if ( !qb.exec() ) {
    akDebug() << "Error during insertion into table" << tableName()
      << qb.query().lastError().text();
    return false;
  }

  setId( qb.insertId() );
  if ( insertId )
    *insertId = id();
  return true;
}

bool PimItem::hasPendingChanges() const
{
  return false
  
    || d->rev_changed
  
    || d->remoteId_changed
  
    || d->remoteRevision_changed
  
    || d->gid_changed
  
    || d->collectionId_changed
  
    || d->mimeTypeId_changed
  
    || d->datetime_changed
  
    || d->atime_changed
  
    || d->dirty_changed
  
    || d->size_changed
  ;
}

// update existing data
bool PimItem::update()
{
  invalidateCache();
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Update );

  
    if ( d->rev_changed ) {
      
      qb.setColumnValue( revColumn(), this->rev() );
    }
  
    if ( d->remoteId_changed ) {
      
      qb.setColumnValue( remoteIdColumn(), this->remoteId() );
    }
  
    if ( d->remoteRevision_changed ) {
      
      qb.setColumnValue( remoteRevisionColumn(), this->remoteRevision() );
    }
  
    if ( d->gid_changed ) {
      
      qb.setColumnValue( gidColumn(), this->gid() );
    }
  
    if ( d->collectionId_changed ) {
      
      if ( d->collectionId <= 0 )
        qb.setColumnValue( collectionIdColumn(), QVariant() );
      else
      
      qb.setColumnValue( collectionIdColumn(), this->collectionId() );
    }
  
    if ( d->mimeTypeId_changed ) {
      
      if ( d->mimeTypeId <= 0 )
        qb.setColumnValue( mimeTypeIdColumn(), QVariant() );
      else
      
      qb.setColumnValue( mimeTypeIdColumn(), this->mimeTypeId() );
    }
  
    if ( d->datetime_changed ) {
      
      qb.setColumnValue( datetimeColumn(), this->datetime() );
    }
  
    if ( d->atime_changed ) {
      
      qb.setColumnValue( atimeColumn(), this->atime() );
    }
  
    if ( d->dirty_changed ) {
      
      qb.setColumnValue( dirtyColumn(), this->dirty() );
    }
  
    if ( d->size_changed ) {
      
      qb.setColumnValue( sizeColumn(), this->size() );
    }
  
  qb.addValueCondition( QLatin1String("id"), Query::Equals, id() );
  

  if ( !qb.exec() ) {
    akDebug() << "Error during updating record with id" << id()
             << " in table" << tableName() << qb.query().lastError().text();
    return false;
  }
  return true;
}

// delete records
bool PimItem::remove( const QString &column, const QVariant &value )
{
  invalidateCompleteCache();
  return Entity::remove<PimItem>( column, value );
}


bool PimItem::remove()
{
  invalidateCache();
  return Entity::remove<PimItem>( idColumn(), id() );
}

bool PimItem::remove( qint64 id )
{
  return remove( idColumn(), id );
}


// cache stuff
void PimItem::invalidateCache() const
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::idCache.remove( id() );
    
    Private::cacheMutex.unlock();
  }
}

void PimItem::invalidateCompleteCache()
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::idCache.clear();
    
    Private::cacheMutex.unlock();
  }
}

void PimItem::enableCache( bool enable )
{
  Private::cacheEnabled = enable;
}



// private class
class Flag::Private : public QSharedData
{
  public:
    Private() : QSharedData()
    
      , name()
    
      , name_changed( false )
    
    {}

    
    QString name;
    
    bool name_changed : 1;
    

    static void addToCache( const Flag & entry );

    // cache
    static bool cacheEnabled;
    static QMutex cacheMutex;
    
    static QHash<qint64, Flag > idCache;
    
    static QHash<QString, Flag > nameCache;
    
};


// static members
bool Flag::Private::cacheEnabled = false;
QMutex Flag::Private::cacheMutex;

QHash<qint64, Flag > Flag::Private::idCache;

QHash<QString, Flag > Flag::Private::nameCache;



void Flag::Private::addToCache( const Flag & entry )
{
  Q_ASSERT( cacheEnabled );
  Q_UNUSED( entry ); 
  cacheMutex.lock();
  
  idCache.insert( entry.id(), entry );
  
  nameCache.insert( entry.name(), entry );
  
  cacheMutex.unlock();
}


// constructor
Flag::Flag() : Entity(),
  d( new Private )
{
}

Flag::Flag(
  const QString &name
) :
  Entity(),
  d( new Private )
{

  d->name = name;
  d->name_changed = true;

}

Flag::Flag(
  qint64 id, const QString &name
) :
  Entity( id ),
  d( new Private )
{

  d->name = name;
  d->name_changed = true;

}
Flag::Flag( const Flag & other )
  : Entity( other ), d( other.d )
{
}

// destructor
Flag::~Flag() {}

// assignment operator
Flag& Flag::operator=( const Flag & other )
{
  if ( this != &other ) {
    d = other.d;
    setId( other.id() );
  }
  return *this;
}

// comparisson operator
bool Flag::operator==( const Flag & other ) const
{
  return id() == other.id();
}

// accessor methods
QString Flag::name() const
{
  return d->name;
}

void Flag::
setName( const QString &name )

{
  d->name = name;
  d->name_changed = true;
}



// SQL table information
QString Flag::tableName()
{
  return QLatin1String( "FlagTable" );
}

QStringList Flag::columnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "id" ) );
  
  rv.append( QLatin1String( "name" ) );
  
  return rv;
}

QStringList Flag::fullColumnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "FlagTable.id" ) );
  
  rv.append( QLatin1String( "FlagTable.name" ) );
  
  return rv;
}


QString Flag::idColumn()
{
  return QLatin1String( "id" );
}

QString Flag::idFullColumnName()
{
  return tableName() + QLatin1String( ".id" );
}

QString Flag::nameColumn()
{
  return QLatin1String( "name" );
}

QString Flag::nameFullColumnName()
{
  return tableName() + QLatin1String( ".name" );
}



// count records
int Flag::count( const QString &column, const QVariant &value )
{
  return Entity::count<Flag>( column, value );
}

// check existence

bool Flag::exists( qint64 id )
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::idCache.contains( id ) ) {
      Private::cacheMutex.unlock();
      return true;
    }
    Private::cacheMutex.unlock();
  }
  return count( idColumn(), id ) > 0;
}

bool Flag::exists( const QString &name )
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::nameCache.contains( name ) ) {
      Private::cacheMutex.unlock();
      return true;
    }
    Private::cacheMutex.unlock();
  }
  return count( nameColumn(), name ) > 0;
}



// result extraction
QVector< Flag > Flag::extractResult( QSqlQuery & query )
{
  QVector<Flag> rv;
  while ( query.next() ) {
    rv.append( Flag(
      
        (query.isNull(0)) ?
          qint64() :
          
          query.value( 0 ).value<qint64>()
            ,
        (query.isNull(1)) ?
          QString() :
          
          Utils::variantToString( query.value( 1 ) )
            
    ) );
  }
  return rv;
}

// data retrieval
Flag Flag::retrieveById( qint64 id )
{
  
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::idCache.contains( id ) ) {
      const Flag tmp = Private::idCache.value( id );
      Private::cacheMutex.unlock();
      return tmp;
    }
    Private::cacheMutex.unlock();
  }
  
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return Flag();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  qb.addValueCondition( QLatin1String("id"), Query::Equals, id );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of record with id"
      << id << "from table" << tableName()
      << qb.query().lastError().text();
    return Flag();
  }
  if ( !qb.query().next() ) {
    return Flag();
  }

  Flag rv(
  
    (qb.query().isNull(0)) ?
      qint64() :
      
      qb.query().value( 0 ).value<qint64>()
        ,
    (qb.query().isNull(1)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 1 ) )
        
  );
  if ( Private::cacheEnabled ) {
    Private::addToCache( rv );
  }
  return rv;

}

Flag Flag::retrieveByName( const QString &name )
{
  
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::nameCache.contains( name ) ) {
      const Flag tmp = Private::nameCache.value( name );
      Private::cacheMutex.unlock();
      return tmp;
    }
    Private::cacheMutex.unlock();
  }
  
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return Flag();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  qb.addValueCondition( QLatin1String("name"), Query::Equals, name );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of record with name"
      << name << "from table" << tableName()
      << qb.query().lastError().text();
    return Flag();
  }
  if ( !qb.query().next() ) {
    return Flag();
  }

  Flag rv(
  
    (qb.query().isNull(0)) ?
      qint64() :
      
      qb.query().value( 0 ).value<qint64>()
        ,
    (qb.query().isNull(1)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 1 ) )
        
  );
  if ( Private::cacheEnabled ) {
    Private::addToCache( rv );
  }
  return rv;

}


QVector<Flag> Flag::retrieveAll()
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<Flag>();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of all records from table" << tableName()
      << qb.query().lastError().text() << qb.query().lastQuery();
    return QVector<Flag>();
  }
  return extractResult( qb.query() );
}

QVector<Flag> Flag::retrieveFiltered( const QString &key, const QVariant &value )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<Flag>();

  SelectQueryBuilder<Flag> qb;
  if ( value.isNull() )
    qb.addValueCondition( key, Query::Is, QVariant() );
  else
    qb.addValueCondition( key, Query::Equals, value );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of records from table" << tableName()
      << "filtered by" << key << "=" << value
      << qb.query().lastError().text();
    return QVector<Flag>();
  }
  return qb.result();
}

// data retrieval for referenced tables


// data retrieval for inverse referenced tables


#ifndef QT_NO_DEBUG_STREAM
// debug stream operator
QDebug & operator<<( QDebug& d, const Flag& entity )
{
  d << "[Flag: "
  
    << "id = " << entity.id()
    << ", "
    << "name = " << entity.name()
    
    << "]";
  return d;
}
#endif

// inserting new data
bool Flag::insert( qint64* insertId )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Insert );
  
    if ( d->name_changed )
      qb.setColumnValue( nameColumn(), this->name() );
    

  if ( !qb.exec() ) {
    akDebug() << "Error during insertion into table" << tableName()
      << qb.query().lastError().text();
    return false;
  }

  setId( qb.insertId() );
  if ( insertId )
    *insertId = id();
  return true;
}

bool Flag::hasPendingChanges() const
{
  return false
  
    || d->name_changed
  ;
}

// update existing data
bool Flag::update()
{
  invalidateCache();
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Update );

  
    if ( d->name_changed ) {
      
      qb.setColumnValue( nameColumn(), this->name() );
    }
  
  qb.addValueCondition( QLatin1String("id"), Query::Equals, id() );
  

  if ( !qb.exec() ) {
    akDebug() << "Error during updating record with id" << id()
             << " in table" << tableName() << qb.query().lastError().text();
    return false;
  }
  return true;
}

// delete records
bool Flag::remove( const QString &column, const QVariant &value )
{
  invalidateCompleteCache();
  return Entity::remove<Flag>( column, value );
}


bool Flag::remove()
{
  invalidateCache();
  return Entity::remove<Flag>( idColumn(), id() );
}

bool Flag::remove( qint64 id )
{
  return remove( idColumn(), id );
}


// cache stuff
void Flag::invalidateCache() const
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::idCache.remove( id() );
    
    Private::nameCache.remove( name() );
    
    Private::cacheMutex.unlock();
  }
}

void Flag::invalidateCompleteCache()
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::idCache.clear();
    
    Private::nameCache.clear();
    
    Private::cacheMutex.unlock();
  }
}

void Flag::enableCache( bool enable )
{
  Private::cacheEnabled = enable;
}



// private class
class PartType::Private : public QSharedData
{
  public:
    Private() : QSharedData()
    
      , name()
    
      , ns()
    
      , name_changed( false )
    
      , ns_changed( false )
    
    {}

    
    QString name;
    
    QString ns;
    
    bool name_changed : 1;
    
    bool ns_changed : 1;
    

    static void addToCache( const PartType & entry );

    // cache
    static bool cacheEnabled;
    static QMutex cacheMutex;
    
    static QHash<qint64, PartType > idCache;
    
    static QHash<QString, PartType > nameCache;
    
};


// static members
bool PartType::Private::cacheEnabled = false;
QMutex PartType::Private::cacheMutex;

QHash<qint64, PartType > PartType::Private::idCache;

QHash<QString, PartType > PartType::Private::nameCache;



void PartType::Private::addToCache( const PartType & entry )
{
  Q_ASSERT( cacheEnabled );
  Q_UNUSED( entry ); 
  cacheMutex.lock();
  
  idCache.insert( entry.id(), entry );
  
  nameCache.insert( entry.name(), entry );
  
  cacheMutex.unlock();
}


// constructor
PartType::PartType() : Entity(),
  d( new Private )
{
}

PartType::PartType(
  const QString &name, const QString &ns
) :
  Entity(),
  d( new Private )
{

  d->name = name;
  d->name_changed = true;

  d->ns = ns;
  d->ns_changed = true;

}

PartType::PartType(
  qint64 id, const QString &name, const QString &ns
) :
  Entity( id ),
  d( new Private )
{

  d->name = name;
  d->name_changed = true;

  d->ns = ns;
  d->ns_changed = true;

}
PartType::PartType( const PartType & other )
  : Entity( other ), d( other.d )
{
}

// destructor
PartType::~PartType() {}

// assignment operator
PartType& PartType::operator=( const PartType & other )
{
  if ( this != &other ) {
    d = other.d;
    setId( other.id() );
  }
  return *this;
}

// comparisson operator
bool PartType::operator==( const PartType & other ) const
{
  return id() == other.id();
}

// accessor methods
QString PartType::name() const
{
  return d->name;
}

void PartType::
setName( const QString &name )

{
  d->name = name;
  d->name_changed = true;
}

QString PartType::ns() const
{
  return d->ns;
}

void PartType::
setNs( const QString &ns )

{
  d->ns = ns;
  d->ns_changed = true;
}



// SQL table information
QString PartType::tableName()
{
  return QLatin1String( "PartTypeTable" );
}

QStringList PartType::columnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "id" ) );
  
  rv.append( QLatin1String( "name" ) );
  
  rv.append( QLatin1String( "ns" ) );
  
  return rv;
}

QStringList PartType::fullColumnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "PartTypeTable.id" ) );
  
  rv.append( QLatin1String( "PartTypeTable.name" ) );
  
  rv.append( QLatin1String( "PartTypeTable.ns" ) );
  
  return rv;
}


QString PartType::idColumn()
{
  return QLatin1String( "id" );
}

QString PartType::idFullColumnName()
{
  return tableName() + QLatin1String( ".id" );
}

QString PartType::nameColumn()
{
  return QLatin1String( "name" );
}

QString PartType::nameFullColumnName()
{
  return tableName() + QLatin1String( ".name" );
}

QString PartType::nsColumn()
{
  return QLatin1String( "ns" );
}

QString PartType::nsFullColumnName()
{
  return tableName() + QLatin1String( ".ns" );
}



// count records
int PartType::count( const QString &column, const QVariant &value )
{
  return Entity::count<PartType>( column, value );
}

// check existence

bool PartType::exists( qint64 id )
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::idCache.contains( id ) ) {
      Private::cacheMutex.unlock();
      return true;
    }
    Private::cacheMutex.unlock();
  }
  return count( idColumn(), id ) > 0;
}

bool PartType::exists( const QString &name )
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::nameCache.contains( name ) ) {
      Private::cacheMutex.unlock();
      return true;
    }
    Private::cacheMutex.unlock();
  }
  return count( nameColumn(), name ) > 0;
}



// result extraction
QVector< PartType > PartType::extractResult( QSqlQuery & query )
{
  QVector<PartType> rv;
  while ( query.next() ) {
    rv.append( PartType(
      
        (query.isNull(0)) ?
          qint64() :
          
          query.value( 0 ).value<qint64>()
            ,
        (query.isNull(1)) ?
          QString() :
          
          Utils::variantToString( query.value( 1 ) )
            ,
        (query.isNull(2)) ?
          QString() :
          
          Utils::variantToString( query.value( 2 ) )
            
    ) );
  }
  return rv;
}

// data retrieval
PartType PartType::retrieveById( qint64 id )
{
  
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::idCache.contains( id ) ) {
      const PartType tmp = Private::idCache.value( id );
      Private::cacheMutex.unlock();
      return tmp;
    }
    Private::cacheMutex.unlock();
  }
  
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return PartType();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  qb.addValueCondition( QLatin1String("id"), Query::Equals, id );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of record with id"
      << id << "from table" << tableName()
      << qb.query().lastError().text();
    return PartType();
  }
  if ( !qb.query().next() ) {
    return PartType();
  }

  PartType rv(
  
    (qb.query().isNull(0)) ?
      qint64() :
      
      qb.query().value( 0 ).value<qint64>()
        ,
    (qb.query().isNull(1)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 1 ) )
        ,
    (qb.query().isNull(2)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 2 ) )
        
  );
  if ( Private::cacheEnabled ) {
    Private::addToCache( rv );
  }
  return rv;

}

PartType PartType::retrieveByName( const QString &name )
{
  
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::nameCache.contains( name ) ) {
      const PartType tmp = Private::nameCache.value( name );
      Private::cacheMutex.unlock();
      return tmp;
    }
    Private::cacheMutex.unlock();
  }
  
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return PartType();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  qb.addValueCondition( QLatin1String("name"), Query::Equals, name );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of record with name"
      << name << "from table" << tableName()
      << qb.query().lastError().text();
    return PartType();
  }
  if ( !qb.query().next() ) {
    return PartType();
  }

  PartType rv(
  
    (qb.query().isNull(0)) ?
      qint64() :
      
      qb.query().value( 0 ).value<qint64>()
        ,
    (qb.query().isNull(1)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 1 ) )
        ,
    (qb.query().isNull(2)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 2 ) )
        
  );
  if ( Private::cacheEnabled ) {
    Private::addToCache( rv );
  }
  return rv;

}


QVector<PartType> PartType::retrieveAll()
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<PartType>();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of all records from table" << tableName()
      << qb.query().lastError().text() << qb.query().lastQuery();
    return QVector<PartType>();
  }
  return extractResult( qb.query() );
}

QVector<PartType> PartType::retrieveFiltered( const QString &key, const QVariant &value )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<PartType>();

  SelectQueryBuilder<PartType> qb;
  if ( value.isNull() )
    qb.addValueCondition( key, Query::Is, QVariant() );
  else
    qb.addValueCondition( key, Query::Equals, value );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of records from table" << tableName()
      << "filtered by" << key << "=" << value
      << qb.query().lastError().text();
    return QVector<PartType>();
  }
  return qb.result();
}

// data retrieval for referenced tables


// data retrieval for inverse referenced tables


#ifndef QT_NO_DEBUG_STREAM
// debug stream operator
QDebug & operator<<( QDebug& d, const PartType& entity )
{
  d << "[PartType: "
  
    << "id = " << entity.id()
    << ", "
    << "name = " << entity.name()
    << ", "
    << "ns = " << entity.ns()
    
    << "]";
  return d;
}
#endif

// inserting new data
bool PartType::insert( qint64* insertId )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Insert );
  
    if ( d->name_changed )
      qb.setColumnValue( nameColumn(), this->name() );
    
    if ( d->ns_changed )
      qb.setColumnValue( nsColumn(), this->ns() );
    

  if ( !qb.exec() ) {
    akDebug() << "Error during insertion into table" << tableName()
      << qb.query().lastError().text();
    return false;
  }

  setId( qb.insertId() );
  if ( insertId )
    *insertId = id();
  return true;
}

bool PartType::hasPendingChanges() const
{
  return false
  
    || d->name_changed
  
    || d->ns_changed
  ;
}

// update existing data
bool PartType::update()
{
  invalidateCache();
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Update );

  
    if ( d->name_changed ) {
      
      qb.setColumnValue( nameColumn(), this->name() );
    }
  
    if ( d->ns_changed ) {
      
      qb.setColumnValue( nsColumn(), this->ns() );
    }
  
  qb.addValueCondition( QLatin1String("id"), Query::Equals, id() );
  

  if ( !qb.exec() ) {
    akDebug() << "Error during updating record with id" << id()
             << " in table" << tableName() << qb.query().lastError().text();
    return false;
  }
  return true;
}

// delete records
bool PartType::remove( const QString &column, const QVariant &value )
{
  invalidateCompleteCache();
  return Entity::remove<PartType>( column, value );
}


bool PartType::remove()
{
  invalidateCache();
  return Entity::remove<PartType>( idColumn(), id() );
}

bool PartType::remove( qint64 id )
{
  return remove( idColumn(), id );
}


// cache stuff
void PartType::invalidateCache() const
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::idCache.remove( id() );
    
    Private::nameCache.remove( name() );
    
    Private::cacheMutex.unlock();
  }
}

void PartType::invalidateCompleteCache()
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::idCache.clear();
    
    Private::nameCache.clear();
    
    Private::cacheMutex.unlock();
  }
}

void PartType::enableCache( bool enable )
{
  Private::cacheEnabled = enable;
}



// private class
class Part::Private : public QSharedData
{
  public:
    Private() : QSharedData()
    
      , pimItemId( 0 )
    
      , partTypeId( 0 )
    
      , datasize( 0 )
    
      , data()
    
      , version( 0 )
    
      , external( false )
    
      , pimItemId_changed( false )
    
      , partTypeId_changed( false )
    
      , data_changed( false )
    
      , datasize_changed( false )
    
      , version_changed( false )
    
      , external_changed( false )
    
    {}

    
    qint64 pimItemId;
    
    qint64 partTypeId;
    
    qint64 datasize;
    
    QByteArray data;
    
    int version;
    
    bool external : 1;
    
    bool pimItemId_changed : 1;
    
    bool partTypeId_changed : 1;
    
    bool data_changed : 1;
    
    bool datasize_changed : 1;
    
    bool version_changed : 1;
    
    bool external_changed : 1;
    

    static void addToCache( const Part & entry );

    // cache
    static bool cacheEnabled;
    static QMutex cacheMutex;
    
    static QHash<qint64, Part > idCache;
    
};


// static members
bool Part::Private::cacheEnabled = false;
QMutex Part::Private::cacheMutex;

QHash<qint64, Part > Part::Private::idCache;



void Part::Private::addToCache( const Part & entry )
{
  Q_ASSERT( cacheEnabled );
  Q_UNUSED( entry ); 
  cacheMutex.lock();
  
  idCache.insert( entry.id(), entry );
  
  cacheMutex.unlock();
}


// constructor
Part::Part() : Entity(),
  d( new Private )
{
}

Part::Part(
  qint64 pimItemId, qint64 partTypeId, const QByteArray &data, qint64 datasize, int version, bool external
) :
  Entity(),
  d( new Private )
{

  d->pimItemId = pimItemId;
  d->pimItemId_changed = true;

  d->partTypeId = partTypeId;
  d->partTypeId_changed = true;

  d->data = data;
  d->data_changed = true;

  d->datasize = datasize;
  d->datasize_changed = true;

  d->version = version;
  d->version_changed = true;

  d->external = external;
  d->external_changed = true;

}

Part::Part(
  qint64 id, qint64 pimItemId, qint64 partTypeId, const QByteArray &data, qint64 datasize, int version, bool external
) :
  Entity( id ),
  d( new Private )
{

  d->pimItemId = pimItemId;
  d->pimItemId_changed = true;

  d->partTypeId = partTypeId;
  d->partTypeId_changed = true;

  d->data = data;
  d->data_changed = true;

  d->datasize = datasize;
  d->datasize_changed = true;

  d->version = version;
  d->version_changed = true;

  d->external = external;
  d->external_changed = true;

}
Part::Part( const Part & other )
  : Entity( other ), d( other.d )
{
}

// destructor
Part::~Part() {}

// assignment operator
Part& Part::operator=( const Part & other )
{
  if ( this != &other ) {
    d = other.d;
    setId( other.id() );
  }
  return *this;
}

// comparisson operator
bool Part::operator==( const Part & other ) const
{
  return id() == other.id();
}

// accessor methods
qint64 Part::pimItemId() const
{
  return d->pimItemId;
}

void Part::
setPimItemId( qint64 pimItemId )

{
  d->pimItemId = pimItemId;
  d->pimItemId_changed = true;
}

qint64 Part::partTypeId() const
{
  return d->partTypeId;
}

void Part::
setPartTypeId( qint64 partTypeId )

{
  d->partTypeId = partTypeId;
  d->partTypeId_changed = true;
}

QByteArray Part::data() const
{
  return d->data;
}

void Part::
setData( const QByteArray &data )

{
  d->data = data;
  d->data_changed = true;
}

qint64 Part::datasize() const
{
  return d->datasize;
}

void Part::
setDatasize( qint64 datasize )

{
  d->datasize = datasize;
  d->datasize_changed = true;
}

int Part::version() const
{
  return d->version;
}

void Part::
setVersion( int version )

{
  d->version = version;
  d->version_changed = true;
}

bool Part::external() const
{
  return d->external;
}

void Part::
setExternal( bool external )

{
  d->external = external;
  d->external_changed = true;
}



// SQL table information
QString Part::tableName()
{
  return QLatin1String( "PartTable" );
}

QStringList Part::columnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "id" ) );
  
  rv.append( QLatin1String( "pimItemId" ) );
  
  rv.append( QLatin1String( "partTypeId" ) );
  
  rv.append( QLatin1String( "data" ) );
  
  rv.append( QLatin1String( "datasize" ) );
  
  rv.append( QLatin1String( "version" ) );
  
  rv.append( QLatin1String( "external" ) );
  
  return rv;
}

QStringList Part::fullColumnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "PartTable.id" ) );
  
  rv.append( QLatin1String( "PartTable.pimItemId" ) );
  
  rv.append( QLatin1String( "PartTable.partTypeId" ) );
  
  rv.append( QLatin1String( "PartTable.data" ) );
  
  rv.append( QLatin1String( "PartTable.datasize" ) );
  
  rv.append( QLatin1String( "PartTable.version" ) );
  
  rv.append( QLatin1String( "PartTable.external" ) );
  
  return rv;
}


QString Part::idColumn()
{
  return QLatin1String( "id" );
}

QString Part::idFullColumnName()
{
  return tableName() + QLatin1String( ".id" );
}

QString Part::pimItemIdColumn()
{
  return QLatin1String( "pimItemId" );
}

QString Part::pimItemIdFullColumnName()
{
  return tableName() + QLatin1String( ".pimItemId" );
}

QString Part::partTypeIdColumn()
{
  return QLatin1String( "partTypeId" );
}

QString Part::partTypeIdFullColumnName()
{
  return tableName() + QLatin1String( ".partTypeId" );
}

QString Part::dataColumn()
{
  return QLatin1String( "data" );
}

QString Part::dataFullColumnName()
{
  return tableName() + QLatin1String( ".data" );
}

QString Part::datasizeColumn()
{
  return QLatin1String( "datasize" );
}

QString Part::datasizeFullColumnName()
{
  return tableName() + QLatin1String( ".datasize" );
}

QString Part::versionColumn()
{
  return QLatin1String( "version" );
}

QString Part::versionFullColumnName()
{
  return tableName() + QLatin1String( ".version" );
}

QString Part::externalColumn()
{
  return QLatin1String( "external" );
}

QString Part::externalFullColumnName()
{
  return tableName() + QLatin1String( ".external" );
}



// count records
int Part::count( const QString &column, const QVariant &value )
{
  return Entity::count<Part>( column, value );
}

// check existence

bool Part::exists( qint64 id )
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::idCache.contains( id ) ) {
      Private::cacheMutex.unlock();
      return true;
    }
    Private::cacheMutex.unlock();
  }
  return count( idColumn(), id ) > 0;
}



// result extraction
QVector< Part > Part::extractResult( QSqlQuery & query )
{
  QVector<Part> rv;
  while ( query.next() ) {
    rv.append( Part(
      
        (query.isNull(0)) ?
          qint64() :
          
          query.value( 0 ).value<qint64>()
            ,
        (query.isNull(1)) ?
          qint64() :
          
          query.value( 1 ).value<qint64>()
            ,
        (query.isNull(2)) ?
          qint64() :
          
          query.value( 2 ).value<qint64>()
            ,
        (query.isNull(3)) ?
          QByteArray() :
          
          query.value( 3 ).value<QByteArray>()
            ,
        (query.isNull(4)) ?
          qint64() :
          
          query.value( 4 ).value<qint64>()
            ,
        (query.isNull(5)) ?
          int() :
          
          query.value( 5 ).value<int>()
            ,
        (query.isNull(6)) ?
          bool() :
          
          query.value( 6 ).value<bool>()
            
    ) );
  }
  return rv;
}

// data retrieval
Part Part::retrieveById( qint64 id )
{
  
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::idCache.contains( id ) ) {
      const Part tmp = Private::idCache.value( id );
      Private::cacheMutex.unlock();
      return tmp;
    }
    Private::cacheMutex.unlock();
  }
  
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return Part();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  qb.addValueCondition( QLatin1String("id"), Query::Equals, id );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of record with id"
      << id << "from table" << tableName()
      << qb.query().lastError().text();
    return Part();
  }
  if ( !qb.query().next() ) {
    return Part();
  }

  Part rv(
  
    (qb.query().isNull(0)) ?
      qint64() :
      
      qb.query().value( 0 ).value<qint64>()
        ,
    (qb.query().isNull(1)) ?
      qint64() :
      
      qb.query().value( 1 ).value<qint64>()
        ,
    (qb.query().isNull(2)) ?
      qint64() :
      
      qb.query().value( 2 ).value<qint64>()
        ,
    (qb.query().isNull(3)) ?
      QByteArray() :
      
      qb.query().value( 3 ).value<QByteArray>()
        ,
    (qb.query().isNull(4)) ?
      qint64() :
      
      qb.query().value( 4 ).value<qint64>()
        ,
    (qb.query().isNull(5)) ?
      int() :
      
      qb.query().value( 5 ).value<int>()
        ,
    (qb.query().isNull(6)) ?
      bool() :
      
      qb.query().value( 6 ).value<bool>()
        
  );
  if ( Private::cacheEnabled ) {
    Private::addToCache( rv );
  }
  return rv;

}



QVector<Part> Part::retrieveAll()
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<Part>();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of all records from table" << tableName()
      << qb.query().lastError().text() << qb.query().lastQuery();
    return QVector<Part>();
  }
  return extractResult( qb.query() );
}

QVector<Part> Part::retrieveFiltered( const QString &key, const QVariant &value )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<Part>();

  SelectQueryBuilder<Part> qb;
  if ( value.isNull() )
    qb.addValueCondition( key, Query::Is, QVariant() );
  else
    qb.addValueCondition( key, Query::Equals, value );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of records from table" << tableName()
      << "filtered by" << key << "=" << value
      << qb.query().lastError().text();
    return QVector<Part>();
  }
  return qb.result();
}

// data retrieval for referenced tables
PimItem Part::pimItem() const
{
  return PimItem::retrieveById( pimItemId() );
}

void Part::
    setPimItem
    ( const PimItem &value )
{
  d->pimItemId = value.id();
  d->pimItemId_changed = true;
}
PartType Part::partType() const
{
  return PartType::retrieveById( partTypeId() );
}

void Part::
    setPartType
    ( const PartType &value )
{
  d->partTypeId = value.id();
  d->partTypeId_changed = true;
}


// data retrieval for inverse referenced tables


#ifndef QT_NO_DEBUG_STREAM
// debug stream operator
QDebug & operator<<( QDebug& d, const Part& entity )
{
  d << "[Part: "
  
    << "id = " << entity.id()
    << ", "
    << "pimItemId = " << entity.pimItemId()
    << ", "
    << "partTypeId = " << entity.partTypeId()
    << ", "
    << "data = " << entity.data()
    << ", "
    << "datasize = " << entity.datasize()
    << ", "
    << "version = " << entity.version()
    << ", "
    << "external = " << entity.external()
    
    << "]";
  return d;
}
#endif

// inserting new data
bool Part::insert( qint64* insertId )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Insert );
  
    if ( d->pimItemId_changed  && d->pimItemId > 0 )
      qb.setColumnValue( pimItemIdColumn(), this->pimItemId() );
    
    if ( d->partTypeId_changed  && d->partTypeId > 0 )
      qb.setColumnValue( partTypeIdColumn(), this->partTypeId() );
    
    if ( d->data_changed )
      qb.setColumnValue( dataColumn(), this->data() );
    
    if ( d->datasize_changed )
      qb.setColumnValue( datasizeColumn(), this->datasize() );
    
    if ( d->version_changed )
      qb.setColumnValue( versionColumn(), this->version() );
    
    if ( d->external_changed )
      qb.setColumnValue( externalColumn(), this->external() );
    

  if ( !qb.exec() ) {
    akDebug() << "Error during insertion into table" << tableName()
      << qb.query().lastError().text();
    return false;
  }

  setId( qb.insertId() );
  if ( insertId )
    *insertId = id();
  return true;
}

bool Part::hasPendingChanges() const
{
  return false
  
    || d->pimItemId_changed
  
    || d->partTypeId_changed
  
    || d->data_changed
  
    || d->datasize_changed
  
    || d->version_changed
  
    || d->external_changed
  ;
}

// update existing data
bool Part::update()
{
  invalidateCache();
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Update );

  
    if ( d->pimItemId_changed ) {
      
      if ( d->pimItemId <= 0 )
        qb.setColumnValue( pimItemIdColumn(), QVariant() );
      else
      
      qb.setColumnValue( pimItemIdColumn(), this->pimItemId() );
    }
  
    if ( d->partTypeId_changed ) {
      
      if ( d->partTypeId <= 0 )
        qb.setColumnValue( partTypeIdColumn(), QVariant() );
      else
      
      qb.setColumnValue( partTypeIdColumn(), this->partTypeId() );
    }
  
    if ( d->data_changed ) {
      
      qb.setColumnValue( dataColumn(), this->data() );
    }
  
    if ( d->datasize_changed ) {
      
      qb.setColumnValue( datasizeColumn(), this->datasize() );
    }
  
    if ( d->version_changed ) {
      
      qb.setColumnValue( versionColumn(), this->version() );
    }
  
    if ( d->external_changed ) {
      
      qb.setColumnValue( externalColumn(), this->external() );
    }
  
  qb.addValueCondition( QLatin1String("id"), Query::Equals, id() );
  

  if ( !qb.exec() ) {
    akDebug() << "Error during updating record with id" << id()
             << " in table" << tableName() << qb.query().lastError().text();
    return false;
  }
  return true;
}

// delete records
bool Part::remove( const QString &column, const QVariant &value )
{
  invalidateCompleteCache();
  return Entity::remove<Part>( column, value );
}


bool Part::remove()
{
  invalidateCache();
  return Entity::remove<Part>( idColumn(), id() );
}

bool Part::remove( qint64 id )
{
  return remove( idColumn(), id );
}


// cache stuff
void Part::invalidateCache() const
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::idCache.remove( id() );
    
    Private::cacheMutex.unlock();
  }
}

void Part::invalidateCompleteCache()
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::idCache.clear();
    
    Private::cacheMutex.unlock();
  }
}

void Part::enableCache( bool enable )
{
  Private::cacheEnabled = enable;
}



// private class
class CollectionAttribute::Private : public QSharedData
{
  public:
    Private() : QSharedData()
    
      , collectionId( 0 )
    
      , type()
    
      , value()
    
      , collectionId_changed( false )
    
      , type_changed( false )
    
      , value_changed( false )
    
    {}

    
    qint64 collectionId;
    
    QByteArray type;
    
    QByteArray value;
    
    bool collectionId_changed : 1;
    
    bool type_changed : 1;
    
    bool value_changed : 1;
    

    static void addToCache( const CollectionAttribute & entry );

    // cache
    static bool cacheEnabled;
    static QMutex cacheMutex;
    
    static QHash<qint64, CollectionAttribute > idCache;
    
};


// static members
bool CollectionAttribute::Private::cacheEnabled = false;
QMutex CollectionAttribute::Private::cacheMutex;

QHash<qint64, CollectionAttribute > CollectionAttribute::Private::idCache;



void CollectionAttribute::Private::addToCache( const CollectionAttribute & entry )
{
  Q_ASSERT( cacheEnabled );
  Q_UNUSED( entry ); 
  cacheMutex.lock();
  
  idCache.insert( entry.id(), entry );
  
  cacheMutex.unlock();
}


// constructor
CollectionAttribute::CollectionAttribute() : Entity(),
  d( new Private )
{
}

CollectionAttribute::CollectionAttribute(
  qint64 collectionId, const QByteArray &type, const QByteArray &value
) :
  Entity(),
  d( new Private )
{

  d->collectionId = collectionId;
  d->collectionId_changed = true;

  d->type = type;
  d->type_changed = true;

  d->value = value;
  d->value_changed = true;

}

CollectionAttribute::CollectionAttribute(
  qint64 id, qint64 collectionId, const QByteArray &type, const QByteArray &value
) :
  Entity( id ),
  d( new Private )
{

  d->collectionId = collectionId;
  d->collectionId_changed = true;

  d->type = type;
  d->type_changed = true;

  d->value = value;
  d->value_changed = true;

}
CollectionAttribute::CollectionAttribute( const CollectionAttribute & other )
  : Entity( other ), d( other.d )
{
}

// destructor
CollectionAttribute::~CollectionAttribute() {}

// assignment operator
CollectionAttribute& CollectionAttribute::operator=( const CollectionAttribute & other )
{
  if ( this != &other ) {
    d = other.d;
    setId( other.id() );
  }
  return *this;
}

// comparisson operator
bool CollectionAttribute::operator==( const CollectionAttribute & other ) const
{
  return id() == other.id();
}

// accessor methods
qint64 CollectionAttribute::collectionId() const
{
  return d->collectionId;
}

void CollectionAttribute::
setCollectionId( qint64 collectionId )

{
  d->collectionId = collectionId;
  d->collectionId_changed = true;
}

QByteArray CollectionAttribute::type() const
{
  return d->type;
}

void CollectionAttribute::
setType( const QByteArray &type )

{
  d->type = type;
  d->type_changed = true;
}

QByteArray CollectionAttribute::value() const
{
  return d->value;
}

void CollectionAttribute::
setValue( const QByteArray &value )

{
  d->value = value;
  d->value_changed = true;
}



// SQL table information
QString CollectionAttribute::tableName()
{
  return QLatin1String( "CollectionAttributeTable" );
}

QStringList CollectionAttribute::columnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "id" ) );
  
  rv.append( QLatin1String( "collectionId" ) );
  
  rv.append( QLatin1String( "type" ) );
  
  rv.append( QLatin1String( "value" ) );
  
  return rv;
}

QStringList CollectionAttribute::fullColumnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "CollectionAttributeTable.id" ) );
  
  rv.append( QLatin1String( "CollectionAttributeTable.collectionId" ) );
  
  rv.append( QLatin1String( "CollectionAttributeTable.type" ) );
  
  rv.append( QLatin1String( "CollectionAttributeTable.value" ) );
  
  return rv;
}


QString CollectionAttribute::idColumn()
{
  return QLatin1String( "id" );
}

QString CollectionAttribute::idFullColumnName()
{
  return tableName() + QLatin1String( ".id" );
}

QString CollectionAttribute::collectionIdColumn()
{
  return QLatin1String( "collectionId" );
}

QString CollectionAttribute::collectionIdFullColumnName()
{
  return tableName() + QLatin1String( ".collectionId" );
}

QString CollectionAttribute::typeColumn()
{
  return QLatin1String( "type" );
}

QString CollectionAttribute::typeFullColumnName()
{
  return tableName() + QLatin1String( ".type" );
}

QString CollectionAttribute::valueColumn()
{
  return QLatin1String( "value" );
}

QString CollectionAttribute::valueFullColumnName()
{
  return tableName() + QLatin1String( ".value" );
}



// count records
int CollectionAttribute::count( const QString &column, const QVariant &value )
{
  return Entity::count<CollectionAttribute>( column, value );
}

// check existence

bool CollectionAttribute::exists( qint64 id )
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::idCache.contains( id ) ) {
      Private::cacheMutex.unlock();
      return true;
    }
    Private::cacheMutex.unlock();
  }
  return count( idColumn(), id ) > 0;
}



// result extraction
QVector< CollectionAttribute > CollectionAttribute::extractResult( QSqlQuery & query )
{
  QVector<CollectionAttribute> rv;
  while ( query.next() ) {
    rv.append( CollectionAttribute(
      
        (query.isNull(0)) ?
          qint64() :
          
          query.value( 0 ).value<qint64>()
            ,
        (query.isNull(1)) ?
          qint64() :
          
          query.value( 1 ).value<qint64>()
            ,
        (query.isNull(2)) ?
          QByteArray() :
          
          query.value( 2 ).value<QByteArray>()
            ,
        (query.isNull(3)) ?
          QByteArray() :
          
          query.value( 3 ).value<QByteArray>()
            
    ) );
  }
  return rv;
}

// data retrieval
CollectionAttribute CollectionAttribute::retrieveById( qint64 id )
{
  
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::idCache.contains( id ) ) {
      const CollectionAttribute tmp = Private::idCache.value( id );
      Private::cacheMutex.unlock();
      return tmp;
    }
    Private::cacheMutex.unlock();
  }
  
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return CollectionAttribute();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  qb.addValueCondition( QLatin1String("id"), Query::Equals, id );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of record with id"
      << id << "from table" << tableName()
      << qb.query().lastError().text();
    return CollectionAttribute();
  }
  if ( !qb.query().next() ) {
    return CollectionAttribute();
  }

  CollectionAttribute rv(
  
    (qb.query().isNull(0)) ?
      qint64() :
      
      qb.query().value( 0 ).value<qint64>()
        ,
    (qb.query().isNull(1)) ?
      qint64() :
      
      qb.query().value( 1 ).value<qint64>()
        ,
    (qb.query().isNull(2)) ?
      QByteArray() :
      
      qb.query().value( 2 ).value<QByteArray>()
        ,
    (qb.query().isNull(3)) ?
      QByteArray() :
      
      qb.query().value( 3 ).value<QByteArray>()
        
  );
  if ( Private::cacheEnabled ) {
    Private::addToCache( rv );
  }
  return rv;

}



QVector<CollectionAttribute> CollectionAttribute::retrieveAll()
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<CollectionAttribute>();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of all records from table" << tableName()
      << qb.query().lastError().text() << qb.query().lastQuery();
    return QVector<CollectionAttribute>();
  }
  return extractResult( qb.query() );
}

QVector<CollectionAttribute> CollectionAttribute::retrieveFiltered( const QString &key, const QVariant &value )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<CollectionAttribute>();

  SelectQueryBuilder<CollectionAttribute> qb;
  if ( value.isNull() )
    qb.addValueCondition( key, Query::Is, QVariant() );
  else
    qb.addValueCondition( key, Query::Equals, value );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of records from table" << tableName()
      << "filtered by" << key << "=" << value
      << qb.query().lastError().text();
    return QVector<CollectionAttribute>();
  }
  return qb.result();
}

// data retrieval for referenced tables
Collection CollectionAttribute::collection() const
{
  return Collection::retrieveById( collectionId() );
}

void CollectionAttribute::
    setCollection
    ( const Collection &value )
{
  d->collectionId = value.id();
  d->collectionId_changed = true;
}


// data retrieval for inverse referenced tables


#ifndef QT_NO_DEBUG_STREAM
// debug stream operator
QDebug & operator<<( QDebug& d, const CollectionAttribute& entity )
{
  d << "[CollectionAttribute: "
  
    << "id = " << entity.id()
    << ", "
    << "collectionId = " << entity.collectionId()
    << ", "
    << "type = " << entity.type()
    << ", "
    << "value = " << entity.value()
    
    << "]";
  return d;
}
#endif

// inserting new data
bool CollectionAttribute::insert( qint64* insertId )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Insert );
  
    if ( d->collectionId_changed  && d->collectionId > 0 )
      qb.setColumnValue( collectionIdColumn(), this->collectionId() );
    
    if ( d->type_changed )
      qb.setColumnValue( typeColumn(), this->type() );
    
    if ( d->value_changed )
      qb.setColumnValue( valueColumn(), this->value() );
    

  if ( !qb.exec() ) {
    akDebug() << "Error during insertion into table" << tableName()
      << qb.query().lastError().text();
    return false;
  }

  setId( qb.insertId() );
  if ( insertId )
    *insertId = id();
  return true;
}

bool CollectionAttribute::hasPendingChanges() const
{
  return false
  
    || d->collectionId_changed
  
    || d->type_changed
  
    || d->value_changed
  ;
}

// update existing data
bool CollectionAttribute::update()
{
  invalidateCache();
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Update );

  
    if ( d->collectionId_changed ) {
      
      if ( d->collectionId <= 0 )
        qb.setColumnValue( collectionIdColumn(), QVariant() );
      else
      
      qb.setColumnValue( collectionIdColumn(), this->collectionId() );
    }
  
    if ( d->type_changed ) {
      
      qb.setColumnValue( typeColumn(), this->type() );
    }
  
    if ( d->value_changed ) {
      
      qb.setColumnValue( valueColumn(), this->value() );
    }
  
  qb.addValueCondition( QLatin1String("id"), Query::Equals, id() );
  

  if ( !qb.exec() ) {
    akDebug() << "Error during updating record with id" << id()
             << " in table" << tableName() << qb.query().lastError().text();
    return false;
  }
  return true;
}

// delete records
bool CollectionAttribute::remove( const QString &column, const QVariant &value )
{
  invalidateCompleteCache();
  return Entity::remove<CollectionAttribute>( column, value );
}


bool CollectionAttribute::remove()
{
  invalidateCache();
  return Entity::remove<CollectionAttribute>( idColumn(), id() );
}

bool CollectionAttribute::remove( qint64 id )
{
  return remove( idColumn(), id );
}


// cache stuff
void CollectionAttribute::invalidateCache() const
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::idCache.remove( id() );
    
    Private::cacheMutex.unlock();
  }
}

void CollectionAttribute::invalidateCompleteCache()
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::idCache.clear();
    
    Private::cacheMutex.unlock();
  }
}

void CollectionAttribute::enableCache( bool enable )
{
  Private::cacheEnabled = enable;
}



// private class
class TagType::Private : public QSharedData
{
  public:
    Private() : QSharedData()
    
      , name()
    
      , name_changed( false )
    
    {}

    
    QString name;
    
    bool name_changed : 1;
    

    static void addToCache( const TagType & entry );

    // cache
    static bool cacheEnabled;
    static QMutex cacheMutex;
    
    static QHash<qint64, TagType > idCache;
    
    static QHash<QString, TagType > nameCache;
    
};


// static members
bool TagType::Private::cacheEnabled = false;
QMutex TagType::Private::cacheMutex;

QHash<qint64, TagType > TagType::Private::idCache;

QHash<QString, TagType > TagType::Private::nameCache;



void TagType::Private::addToCache( const TagType & entry )
{
  Q_ASSERT( cacheEnabled );
  Q_UNUSED( entry ); 
  cacheMutex.lock();
  
  idCache.insert( entry.id(), entry );
  
  nameCache.insert( entry.name(), entry );
  
  cacheMutex.unlock();
}


// constructor
TagType::TagType() : Entity(),
  d( new Private )
{
}

TagType::TagType(
  const QString &name
) :
  Entity(),
  d( new Private )
{

  d->name = name;
  d->name_changed = true;

}

TagType::TagType(
  qint64 id, const QString &name
) :
  Entity( id ),
  d( new Private )
{

  d->name = name;
  d->name_changed = true;

}
TagType::TagType( const TagType & other )
  : Entity( other ), d( other.d )
{
}

// destructor
TagType::~TagType() {}

// assignment operator
TagType& TagType::operator=( const TagType & other )
{
  if ( this != &other ) {
    d = other.d;
    setId( other.id() );
  }
  return *this;
}

// comparisson operator
bool TagType::operator==( const TagType & other ) const
{
  return id() == other.id();
}

// accessor methods
QString TagType::name() const
{
  return d->name;
}

void TagType::
setName( const QString &name )

{
  d->name = name;
  d->name_changed = true;
}



// SQL table information
QString TagType::tableName()
{
  return QLatin1String( "TagTypeTable" );
}

QStringList TagType::columnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "id" ) );
  
  rv.append( QLatin1String( "name" ) );
  
  return rv;
}

QStringList TagType::fullColumnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "TagTypeTable.id" ) );
  
  rv.append( QLatin1String( "TagTypeTable.name" ) );
  
  return rv;
}


QString TagType::idColumn()
{
  return QLatin1String( "id" );
}

QString TagType::idFullColumnName()
{
  return tableName() + QLatin1String( ".id" );
}

QString TagType::nameColumn()
{
  return QLatin1String( "name" );
}

QString TagType::nameFullColumnName()
{
  return tableName() + QLatin1String( ".name" );
}



// count records
int TagType::count( const QString &column, const QVariant &value )
{
  return Entity::count<TagType>( column, value );
}

// check existence

bool TagType::exists( qint64 id )
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::idCache.contains( id ) ) {
      Private::cacheMutex.unlock();
      return true;
    }
    Private::cacheMutex.unlock();
  }
  return count( idColumn(), id ) > 0;
}

bool TagType::exists( const QString &name )
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::nameCache.contains( name ) ) {
      Private::cacheMutex.unlock();
      return true;
    }
    Private::cacheMutex.unlock();
  }
  return count( nameColumn(), name ) > 0;
}



// result extraction
QVector< TagType > TagType::extractResult( QSqlQuery & query )
{
  QVector<TagType> rv;
  while ( query.next() ) {
    rv.append( TagType(
      
        (query.isNull(0)) ?
          qint64() :
          
          query.value( 0 ).value<qint64>()
            ,
        (query.isNull(1)) ?
          QString() :
          
          Utils::variantToString( query.value( 1 ) )
            
    ) );
  }
  return rv;
}

// data retrieval
TagType TagType::retrieveById( qint64 id )
{
  
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::idCache.contains( id ) ) {
      const TagType tmp = Private::idCache.value( id );
      Private::cacheMutex.unlock();
      return tmp;
    }
    Private::cacheMutex.unlock();
  }
  
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return TagType();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  qb.addValueCondition( QLatin1String("id"), Query::Equals, id );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of record with id"
      << id << "from table" << tableName()
      << qb.query().lastError().text();
    return TagType();
  }
  if ( !qb.query().next() ) {
    return TagType();
  }

  TagType rv(
  
    (qb.query().isNull(0)) ?
      qint64() :
      
      qb.query().value( 0 ).value<qint64>()
        ,
    (qb.query().isNull(1)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 1 ) )
        
  );
  if ( Private::cacheEnabled ) {
    Private::addToCache( rv );
  }
  return rv;

}

TagType TagType::retrieveByName( const QString &name )
{
  
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::nameCache.contains( name ) ) {
      const TagType tmp = Private::nameCache.value( name );
      Private::cacheMutex.unlock();
      return tmp;
    }
    Private::cacheMutex.unlock();
  }
  
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return TagType();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  qb.addValueCondition( QLatin1String("name"), Query::Equals, name );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of record with name"
      << name << "from table" << tableName()
      << qb.query().lastError().text();
    return TagType();
  }
  if ( !qb.query().next() ) {
    return TagType();
  }

  TagType rv(
  
    (qb.query().isNull(0)) ?
      qint64() :
      
      qb.query().value( 0 ).value<qint64>()
        ,
    (qb.query().isNull(1)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 1 ) )
        
  );
  if ( Private::cacheEnabled ) {
    Private::addToCache( rv );
  }
  return rv;

}


QVector<TagType> TagType::retrieveAll()
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<TagType>();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of all records from table" << tableName()
      << qb.query().lastError().text() << qb.query().lastQuery();
    return QVector<TagType>();
  }
  return extractResult( qb.query() );
}

QVector<TagType> TagType::retrieveFiltered( const QString &key, const QVariant &value )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<TagType>();

  SelectQueryBuilder<TagType> qb;
  if ( value.isNull() )
    qb.addValueCondition( key, Query::Is, QVariant() );
  else
    qb.addValueCondition( key, Query::Equals, value );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of records from table" << tableName()
      << "filtered by" << key << "=" << value
      << qb.query().lastError().text();
    return QVector<TagType>();
  }
  return qb.result();
}

// data retrieval for referenced tables


// data retrieval for inverse referenced tables


#ifndef QT_NO_DEBUG_STREAM
// debug stream operator
QDebug & operator<<( QDebug& d, const TagType& entity )
{
  d << "[TagType: "
  
    << "id = " << entity.id()
    << ", "
    << "name = " << entity.name()
    
    << "]";
  return d;
}
#endif

// inserting new data
bool TagType::insert( qint64* insertId )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Insert );
  
    if ( d->name_changed )
      qb.setColumnValue( nameColumn(), this->name() );
    

  if ( !qb.exec() ) {
    akDebug() << "Error during insertion into table" << tableName()
      << qb.query().lastError().text();
    return false;
  }

  setId( qb.insertId() );
  if ( insertId )
    *insertId = id();
  return true;
}

bool TagType::hasPendingChanges() const
{
  return false
  
    || d->name_changed
  ;
}

// update existing data
bool TagType::update()
{
  invalidateCache();
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Update );

  
    if ( d->name_changed ) {
      
      qb.setColumnValue( nameColumn(), this->name() );
    }
  
  qb.addValueCondition( QLatin1String("id"), Query::Equals, id() );
  

  if ( !qb.exec() ) {
    akDebug() << "Error during updating record with id" << id()
             << " in table" << tableName() << qb.query().lastError().text();
    return false;
  }
  return true;
}

// delete records
bool TagType::remove( const QString &column, const QVariant &value )
{
  invalidateCompleteCache();
  return Entity::remove<TagType>( column, value );
}


bool TagType::remove()
{
  invalidateCache();
  return Entity::remove<TagType>( idColumn(), id() );
}

bool TagType::remove( qint64 id )
{
  return remove( idColumn(), id );
}


// cache stuff
void TagType::invalidateCache() const
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::idCache.remove( id() );
    
    Private::nameCache.remove( name() );
    
    Private::cacheMutex.unlock();
  }
}

void TagType::invalidateCompleteCache()
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::idCache.clear();
    
    Private::nameCache.clear();
    
    Private::cacheMutex.unlock();
  }
}

void TagType::enableCache( bool enable )
{
  Private::cacheEnabled = enable;
}



// private class
class Tag::Private : public QSharedData
{
  public:
    Private() : QSharedData()
    
      , parentId( 0 )
    
      , typeId( 1 )
    
      , gid()
    
      , gid_changed( false )
    
      , parentId_changed( false )
    
      , typeId_changed( false )
    
    {}

    
    qint64 parentId;
    
    qint64 typeId;
    
    QString gid;
    
    bool gid_changed : 1;
    
    bool parentId_changed : 1;
    
    bool typeId_changed : 1;
    

    static void addToCache( const Tag & entry );

    // cache
    static bool cacheEnabled;
    static QMutex cacheMutex;
    
    static QHash<qint64, Tag > idCache;
    
};


// static members
bool Tag::Private::cacheEnabled = false;
QMutex Tag::Private::cacheMutex;

QHash<qint64, Tag > Tag::Private::idCache;



void Tag::Private::addToCache( const Tag & entry )
{
  Q_ASSERT( cacheEnabled );
  Q_UNUSED( entry ); 
  cacheMutex.lock();
  
  idCache.insert( entry.id(), entry );
  
  cacheMutex.unlock();
}


// constructor
Tag::Tag() : Entity(),
  d( new Private )
{
}

Tag::Tag(
  const QString &gid, qint64 parentId, qint64 typeId
) :
  Entity(),
  d( new Private )
{

  d->gid = gid;
  d->gid_changed = true;

  d->parentId = parentId;
  d->parentId_changed = true;

  d->typeId = typeId;
  d->typeId_changed = true;

}

Tag::Tag(
  qint64 id, const QString &gid, qint64 parentId, qint64 typeId
) :
  Entity( id ),
  d( new Private )
{

  d->gid = gid;
  d->gid_changed = true;

  d->parentId = parentId;
  d->parentId_changed = true;

  d->typeId = typeId;
  d->typeId_changed = true;

}
Tag::Tag( const Tag & other )
  : Entity( other ), d( other.d )
{
}

// destructor
Tag::~Tag() {}

// assignment operator
Tag& Tag::operator=( const Tag & other )
{
  if ( this != &other ) {
    d = other.d;
    setId( other.id() );
  }
  return *this;
}

// comparisson operator
bool Tag::operator==( const Tag & other ) const
{
  return id() == other.id();
}

// accessor methods
QString Tag::gid() const
{
  return d->gid;
}

void Tag::
setGid( const QString &gid )

{
  d->gid = gid;
  d->gid_changed = true;
}

qint64 Tag::parentId() const
{
  return d->parentId;
}

void Tag::
setParentId( qint64 parentId )

{
  d->parentId = parentId;
  d->parentId_changed = true;
}

qint64 Tag::typeId() const
{
  return d->typeId;
}

void Tag::
setTypeId( qint64 typeId )

{
  d->typeId = typeId;
  d->typeId_changed = true;
}



// SQL table information
QString Tag::tableName()
{
  return QLatin1String( "TagTable" );
}

QStringList Tag::columnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "id" ) );
  
  rv.append( QLatin1String( "gid" ) );
  
  rv.append( QLatin1String( "parentId" ) );
  
  rv.append( QLatin1String( "typeId" ) );
  
  return rv;
}

QStringList Tag::fullColumnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "TagTable.id" ) );
  
  rv.append( QLatin1String( "TagTable.gid" ) );
  
  rv.append( QLatin1String( "TagTable.parentId" ) );
  
  rv.append( QLatin1String( "TagTable.typeId" ) );
  
  return rv;
}


QString Tag::idColumn()
{
  return QLatin1String( "id" );
}

QString Tag::idFullColumnName()
{
  return tableName() + QLatin1String( ".id" );
}

QString Tag::gidColumn()
{
  return QLatin1String( "gid" );
}

QString Tag::gidFullColumnName()
{
  return tableName() + QLatin1String( ".gid" );
}

QString Tag::parentIdColumn()
{
  return QLatin1String( "parentId" );
}

QString Tag::parentIdFullColumnName()
{
  return tableName() + QLatin1String( ".parentId" );
}

QString Tag::typeIdColumn()
{
  return QLatin1String( "typeId" );
}

QString Tag::typeIdFullColumnName()
{
  return tableName() + QLatin1String( ".typeId" );
}



// count records
int Tag::count( const QString &column, const QVariant &value )
{
  return Entity::count<Tag>( column, value );
}

// check existence

bool Tag::exists( qint64 id )
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::idCache.contains( id ) ) {
      Private::cacheMutex.unlock();
      return true;
    }
    Private::cacheMutex.unlock();
  }
  return count( idColumn(), id ) > 0;
}



// result extraction
QVector< Tag > Tag::extractResult( QSqlQuery & query )
{
  QVector<Tag> rv;
  while ( query.next() ) {
    rv.append( Tag(
      
        (query.isNull(0)) ?
          qint64() :
          
          query.value( 0 ).value<qint64>()
            ,
        (query.isNull(1)) ?
          QString() :
          
          Utils::variantToString( query.value( 1 ) )
            ,
        (query.isNull(2)) ?
          qint64() :
          
          query.value( 2 ).value<qint64>()
            ,
        (query.isNull(3)) ?
          qint64() :
          
          query.value( 3 ).value<qint64>()
            
    ) );
  }
  return rv;
}

// data retrieval
Tag Tag::retrieveById( qint64 id )
{
  
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::idCache.contains( id ) ) {
      const Tag tmp = Private::idCache.value( id );
      Private::cacheMutex.unlock();
      return tmp;
    }
    Private::cacheMutex.unlock();
  }
  
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return Tag();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  qb.addValueCondition( QLatin1String("id"), Query::Equals, id );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of record with id"
      << id << "from table" << tableName()
      << qb.query().lastError().text();
    return Tag();
  }
  if ( !qb.query().next() ) {
    return Tag();
  }

  Tag rv(
  
    (qb.query().isNull(0)) ?
      qint64() :
      
      qb.query().value( 0 ).value<qint64>()
        ,
    (qb.query().isNull(1)) ?
      QString() :
      
      Utils::variantToString( qb.query().value( 1 ) )
        ,
    (qb.query().isNull(2)) ?
      qint64() :
      
      qb.query().value( 2 ).value<qint64>()
        ,
    (qb.query().isNull(3)) ?
      qint64() :
      
      qb.query().value( 3 ).value<qint64>()
        
  );
  if ( Private::cacheEnabled ) {
    Private::addToCache( rv );
  }
  return rv;

}



QVector<Tag> Tag::retrieveAll()
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<Tag>();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of all records from table" << tableName()
      << qb.query().lastError().text() << qb.query().lastQuery();
    return QVector<Tag>();
  }
  return extractResult( qb.query() );
}

QVector<Tag> Tag::retrieveFiltered( const QString &key, const QVariant &value )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<Tag>();

  SelectQueryBuilder<Tag> qb;
  if ( value.isNull() )
    qb.addValueCondition( key, Query::Is, QVariant() );
  else
    qb.addValueCondition( key, Query::Equals, value );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of records from table" << tableName()
      << "filtered by" << key << "=" << value
      << qb.query().lastError().text();
    return QVector<Tag>();
  }
  return qb.result();
}

// data retrieval for referenced tables
Tag Tag::parent() const
{
  return Tag::retrieveById( parentId() );
}

void Tag::
    setParent
    ( const Tag &value )
{
  d->parentId = value.id();
  d->parentId_changed = true;
}
TagType Tag::tagType() const
{
  return TagType::retrieveById( typeId() );
}

void Tag::
    setTagType
    ( const TagType &value )
{
  d->typeId = value.id();
  d->typeId_changed = true;
}


// data retrieval for inverse referenced tables


#ifndef QT_NO_DEBUG_STREAM
// debug stream operator
QDebug & operator<<( QDebug& d, const Tag& entity )
{
  d << "[Tag: "
  
    << "id = " << entity.id()
    << ", "
    << "gid = " << entity.gid()
    << ", "
    << "parentId = " << entity.parentId()
    << ", "
    << "typeId = " << entity.typeId()
    
    << "]";
  return d;
}
#endif

// inserting new data
bool Tag::insert( qint64* insertId )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Insert );
  
    if ( d->gid_changed )
      qb.setColumnValue( gidColumn(), this->gid() );
    
    if ( d->parentId_changed  && d->parentId > 0 )
      qb.setColumnValue( parentIdColumn(), this->parentId() );
    
    if ( d->typeId_changed  && d->typeId > 0 )
      qb.setColumnValue( typeIdColumn(), this->typeId() );
    

  if ( !qb.exec() ) {
    akDebug() << "Error during insertion into table" << tableName()
      << qb.query().lastError().text();
    return false;
  }

  setId( qb.insertId() );
  if ( insertId )
    *insertId = id();
  return true;
}

bool Tag::hasPendingChanges() const
{
  return false
  
    || d->gid_changed
  
    || d->parentId_changed
  
    || d->typeId_changed
  ;
}

// update existing data
bool Tag::update()
{
  invalidateCache();
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Update );

  
    if ( d->gid_changed ) {
      
      qb.setColumnValue( gidColumn(), this->gid() );
    }
  
    if ( d->parentId_changed ) {
      
      if ( d->parentId <= 0 )
        qb.setColumnValue( parentIdColumn(), QVariant() );
      else
      
      qb.setColumnValue( parentIdColumn(), this->parentId() );
    }
  
    if ( d->typeId_changed ) {
      
      if ( d->typeId <= 0 )
        qb.setColumnValue( typeIdColumn(), QVariant() );
      else
      
      qb.setColumnValue( typeIdColumn(), this->typeId() );
    }
  
  qb.addValueCondition( QLatin1String("id"), Query::Equals, id() );
  

  if ( !qb.exec() ) {
    akDebug() << "Error during updating record with id" << id()
             << " in table" << tableName() << qb.query().lastError().text();
    return false;
  }
  return true;
}

// delete records
bool Tag::remove( const QString &column, const QVariant &value )
{
  invalidateCompleteCache();
  return Entity::remove<Tag>( column, value );
}


bool Tag::remove()
{
  invalidateCache();
  return Entity::remove<Tag>( idColumn(), id() );
}

bool Tag::remove( qint64 id )
{
  return remove( idColumn(), id );
}


// cache stuff
void Tag::invalidateCache() const
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::idCache.remove( id() );
    
    Private::cacheMutex.unlock();
  }
}

void Tag::invalidateCompleteCache()
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::idCache.clear();
    
    Private::cacheMutex.unlock();
  }
}

void Tag::enableCache( bool enable )
{
  Private::cacheEnabled = enable;
}



// private class
class TagAttribute::Private : public QSharedData
{
  public:
    Private() : QSharedData()
    
      , tagId( 0 )
    
      , type()
    
      , value()
    
      , tagId_changed( false )
    
      , type_changed( false )
    
      , value_changed( false )
    
    {}

    
    qint64 tagId;
    
    QByteArray type;
    
    QByteArray value;
    
    bool tagId_changed : 1;
    
    bool type_changed : 1;
    
    bool value_changed : 1;
    

    static void addToCache( const TagAttribute & entry );

    // cache
    static bool cacheEnabled;
    static QMutex cacheMutex;
    
    static QHash<qint64, TagAttribute > idCache;
    
};


// static members
bool TagAttribute::Private::cacheEnabled = false;
QMutex TagAttribute::Private::cacheMutex;

QHash<qint64, TagAttribute > TagAttribute::Private::idCache;



void TagAttribute::Private::addToCache( const TagAttribute & entry )
{
  Q_ASSERT( cacheEnabled );
  Q_UNUSED( entry ); 
  cacheMutex.lock();
  
  idCache.insert( entry.id(), entry );
  
  cacheMutex.unlock();
}


// constructor
TagAttribute::TagAttribute() : Entity(),
  d( new Private )
{
}

TagAttribute::TagAttribute(
  qint64 tagId, const QByteArray &type, const QByteArray &value
) :
  Entity(),
  d( new Private )
{

  d->tagId = tagId;
  d->tagId_changed = true;

  d->type = type;
  d->type_changed = true;

  d->value = value;
  d->value_changed = true;

}

TagAttribute::TagAttribute(
  qint64 id, qint64 tagId, const QByteArray &type, const QByteArray &value
) :
  Entity( id ),
  d( new Private )
{

  d->tagId = tagId;
  d->tagId_changed = true;

  d->type = type;
  d->type_changed = true;

  d->value = value;
  d->value_changed = true;

}
TagAttribute::TagAttribute( const TagAttribute & other )
  : Entity( other ), d( other.d )
{
}

// destructor
TagAttribute::~TagAttribute() {}

// assignment operator
TagAttribute& TagAttribute::operator=( const TagAttribute & other )
{
  if ( this != &other ) {
    d = other.d;
    setId( other.id() );
  }
  return *this;
}

// comparisson operator
bool TagAttribute::operator==( const TagAttribute & other ) const
{
  return id() == other.id();
}

// accessor methods
qint64 TagAttribute::tagId() const
{
  return d->tagId;
}

void TagAttribute::
setTagId( qint64 tagId )

{
  d->tagId = tagId;
  d->tagId_changed = true;
}

QByteArray TagAttribute::type() const
{
  return d->type;
}

void TagAttribute::
setType( const QByteArray &type )

{
  d->type = type;
  d->type_changed = true;
}

QByteArray TagAttribute::value() const
{
  return d->value;
}

void TagAttribute::
setValue( const QByteArray &value )

{
  d->value = value;
  d->value_changed = true;
}



// SQL table information
QString TagAttribute::tableName()
{
  return QLatin1String( "TagAttributeTable" );
}

QStringList TagAttribute::columnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "id" ) );
  
  rv.append( QLatin1String( "tagId" ) );
  
  rv.append( QLatin1String( "type" ) );
  
  rv.append( QLatin1String( "value" ) );
  
  return rv;
}

QStringList TagAttribute::fullColumnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "TagAttributeTable.id" ) );
  
  rv.append( QLatin1String( "TagAttributeTable.tagId" ) );
  
  rv.append( QLatin1String( "TagAttributeTable.type" ) );
  
  rv.append( QLatin1String( "TagAttributeTable.value" ) );
  
  return rv;
}


QString TagAttribute::idColumn()
{
  return QLatin1String( "id" );
}

QString TagAttribute::idFullColumnName()
{
  return tableName() + QLatin1String( ".id" );
}

QString TagAttribute::tagIdColumn()
{
  return QLatin1String( "tagId" );
}

QString TagAttribute::tagIdFullColumnName()
{
  return tableName() + QLatin1String( ".tagId" );
}

QString TagAttribute::typeColumn()
{
  return QLatin1String( "type" );
}

QString TagAttribute::typeFullColumnName()
{
  return tableName() + QLatin1String( ".type" );
}

QString TagAttribute::valueColumn()
{
  return QLatin1String( "value" );
}

QString TagAttribute::valueFullColumnName()
{
  return tableName() + QLatin1String( ".value" );
}



// count records
int TagAttribute::count( const QString &column, const QVariant &value )
{
  return Entity::count<TagAttribute>( column, value );
}

// check existence

bool TagAttribute::exists( qint64 id )
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::idCache.contains( id ) ) {
      Private::cacheMutex.unlock();
      return true;
    }
    Private::cacheMutex.unlock();
  }
  return count( idColumn(), id ) > 0;
}



// result extraction
QVector< TagAttribute > TagAttribute::extractResult( QSqlQuery & query )
{
  QVector<TagAttribute> rv;
  while ( query.next() ) {
    rv.append( TagAttribute(
      
        (query.isNull(0)) ?
          qint64() :
          
          query.value( 0 ).value<qint64>()
            ,
        (query.isNull(1)) ?
          qint64() :
          
          query.value( 1 ).value<qint64>()
            ,
        (query.isNull(2)) ?
          QByteArray() :
          
          query.value( 2 ).value<QByteArray>()
            ,
        (query.isNull(3)) ?
          QByteArray() :
          
          query.value( 3 ).value<QByteArray>()
            
    ) );
  }
  return rv;
}

// data retrieval
TagAttribute TagAttribute::retrieveById( qint64 id )
{
  
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    if ( Private::idCache.contains( id ) ) {
      const TagAttribute tmp = Private::idCache.value( id );
      Private::cacheMutex.unlock();
      return tmp;
    }
    Private::cacheMutex.unlock();
  }
  
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return TagAttribute();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  qb.addValueCondition( QLatin1String("id"), Query::Equals, id );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of record with id"
      << id << "from table" << tableName()
      << qb.query().lastError().text();
    return TagAttribute();
  }
  if ( !qb.query().next() ) {
    return TagAttribute();
  }

  TagAttribute rv(
  
    (qb.query().isNull(0)) ?
      qint64() :
      
      qb.query().value( 0 ).value<qint64>()
        ,
    (qb.query().isNull(1)) ?
      qint64() :
      
      qb.query().value( 1 ).value<qint64>()
        ,
    (qb.query().isNull(2)) ?
      QByteArray() :
      
      qb.query().value( 2 ).value<QByteArray>()
        ,
    (qb.query().isNull(3)) ?
      QByteArray() :
      
      qb.query().value( 3 ).value<QByteArray>()
        
  );
  if ( Private::cacheEnabled ) {
    Private::addToCache( rv );
  }
  return rv;

}



QVector<TagAttribute> TagAttribute::retrieveAll()
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<TagAttribute>();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of all records from table" << tableName()
      << qb.query().lastError().text() << qb.query().lastQuery();
    return QVector<TagAttribute>();
  }
  return extractResult( qb.query() );
}

QVector<TagAttribute> TagAttribute::retrieveFiltered( const QString &key, const QVariant &value )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<TagAttribute>();

  SelectQueryBuilder<TagAttribute> qb;
  if ( value.isNull() )
    qb.addValueCondition( key, Query::Is, QVariant() );
  else
    qb.addValueCondition( key, Query::Equals, value );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of records from table" << tableName()
      << "filtered by" << key << "=" << value
      << qb.query().lastError().text();
    return QVector<TagAttribute>();
  }
  return qb.result();
}

// data retrieval for referenced tables
Tag TagAttribute::tag() const
{
  return Tag::retrieveById( tagId() );
}

void TagAttribute::
    setTag
    ( const Tag &value )
{
  d->tagId = value.id();
  d->tagId_changed = true;
}


// data retrieval for inverse referenced tables


#ifndef QT_NO_DEBUG_STREAM
// debug stream operator
QDebug & operator<<( QDebug& d, const TagAttribute& entity )
{
  d << "[TagAttribute: "
  
    << "id = " << entity.id()
    << ", "
    << "tagId = " << entity.tagId()
    << ", "
    << "type = " << entity.type()
    << ", "
    << "value = " << entity.value()
    
    << "]";
  return d;
}
#endif

// inserting new data
bool TagAttribute::insert( qint64* insertId )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Insert );
  
    if ( d->tagId_changed  && d->tagId > 0 )
      qb.setColumnValue( tagIdColumn(), this->tagId() );
    
    if ( d->type_changed )
      qb.setColumnValue( typeColumn(), this->type() );
    
    if ( d->value_changed )
      qb.setColumnValue( valueColumn(), this->value() );
    

  if ( !qb.exec() ) {
    akDebug() << "Error during insertion into table" << tableName()
      << qb.query().lastError().text();
    return false;
  }

  setId( qb.insertId() );
  if ( insertId )
    *insertId = id();
  return true;
}

bool TagAttribute::hasPendingChanges() const
{
  return false
  
    || d->tagId_changed
  
    || d->type_changed
  
    || d->value_changed
  ;
}

// update existing data
bool TagAttribute::update()
{
  invalidateCache();
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Update );

  
    if ( d->tagId_changed ) {
      
      if ( d->tagId <= 0 )
        qb.setColumnValue( tagIdColumn(), QVariant() );
      else
      
      qb.setColumnValue( tagIdColumn(), this->tagId() );
    }
  
    if ( d->type_changed ) {
      
      qb.setColumnValue( typeColumn(), this->type() );
    }
  
    if ( d->value_changed ) {
      
      qb.setColumnValue( valueColumn(), this->value() );
    }
  
  qb.addValueCondition( QLatin1String("id"), Query::Equals, id() );
  

  if ( !qb.exec() ) {
    akDebug() << "Error during updating record with id" << id()
             << " in table" << tableName() << qb.query().lastError().text();
    return false;
  }
  return true;
}

// delete records
bool TagAttribute::remove( const QString &column, const QVariant &value )
{
  invalidateCompleteCache();
  return Entity::remove<TagAttribute>( column, value );
}


bool TagAttribute::remove()
{
  invalidateCache();
  return Entity::remove<TagAttribute>( idColumn(), id() );
}

bool TagAttribute::remove( qint64 id )
{
  return remove( idColumn(), id );
}


// cache stuff
void TagAttribute::invalidateCache() const
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::idCache.remove( id() );
    
    Private::cacheMutex.unlock();
  }
}

void TagAttribute::invalidateCompleteCache()
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::idCache.clear();
    
    Private::cacheMutex.unlock();
  }
}

void TagAttribute::enableCache( bool enable )
{
  Private::cacheEnabled = enable;
}



// private class
class TagRemoteIdResourceRelation::Private : public QSharedData
{
  public:
    Private() : QSharedData()
    
      , tagId( 0 )
    
      , resourceId( 0 )
    
      , remoteId()
    
      , tagId_changed( false )
    
      , resourceId_changed( false )
    
      , remoteId_changed( false )
    
    {}

    
    qint64 tagId;
    
    qint64 resourceId;
    
    QString remoteId;
    
    bool tagId_changed : 1;
    
    bool resourceId_changed : 1;
    
    bool remoteId_changed : 1;
    

    static void addToCache( const TagRemoteIdResourceRelation & entry );

    // cache
    static bool cacheEnabled;
    static QMutex cacheMutex;
    
};


// static members
bool TagRemoteIdResourceRelation::Private::cacheEnabled = false;
QMutex TagRemoteIdResourceRelation::Private::cacheMutex;



void TagRemoteIdResourceRelation::Private::addToCache( const TagRemoteIdResourceRelation & entry )
{
  Q_ASSERT( cacheEnabled );
  Q_UNUSED( entry ); 
  cacheMutex.lock();
  
  cacheMutex.unlock();
}


// constructor
TagRemoteIdResourceRelation::TagRemoteIdResourceRelation() : Entity(),
  d( new Private )
{
}

TagRemoteIdResourceRelation::TagRemoteIdResourceRelation(
  qint64 tagId, qint64 resourceId, const QString &remoteId
) :
  Entity(),
  d( new Private )
{

  d->tagId = tagId;
  d->tagId_changed = true;

  d->resourceId = resourceId;
  d->resourceId_changed = true;

  d->remoteId = remoteId;
  d->remoteId_changed = true;

}

TagRemoteIdResourceRelation::TagRemoteIdResourceRelation( const TagRemoteIdResourceRelation & other )
  : Entity( other ), d( other.d )
{
}

// destructor
TagRemoteIdResourceRelation::~TagRemoteIdResourceRelation() {}

// assignment operator
TagRemoteIdResourceRelation& TagRemoteIdResourceRelation::operator=( const TagRemoteIdResourceRelation & other )
{
  if ( this != &other ) {
    d = other.d;
    setId( other.id() );
  }
  return *this;
}

// comparisson operator
bool TagRemoteIdResourceRelation::operator==( const TagRemoteIdResourceRelation & other ) const
{
  return id() == other.id();
}

// accessor methods
qint64 TagRemoteIdResourceRelation::tagId() const
{
  return d->tagId;
}

void TagRemoteIdResourceRelation::
setTagId( qint64 tagId )

{
  d->tagId = tagId;
  d->tagId_changed = true;
}

qint64 TagRemoteIdResourceRelation::resourceId() const
{
  return d->resourceId;
}

void TagRemoteIdResourceRelation::
setResourceId( qint64 resourceId )

{
  d->resourceId = resourceId;
  d->resourceId_changed = true;
}

QString TagRemoteIdResourceRelation::remoteId() const
{
  return d->remoteId;
}

void TagRemoteIdResourceRelation::
setRemoteId( const QString &remoteId )

{
  d->remoteId = remoteId;
  d->remoteId_changed = true;
}



// SQL table information
QString TagRemoteIdResourceRelation::tableName()
{
  return QLatin1String( "TagRemoteIdResourceRelationTable" );
}

QStringList TagRemoteIdResourceRelation::columnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "tagId" ) );
  
  rv.append( QLatin1String( "resourceId" ) );
  
  rv.append( QLatin1String( "remoteId" ) );
  
  return rv;
}

QStringList TagRemoteIdResourceRelation::fullColumnNames()
{
  QStringList rv;
  
  rv.append( QLatin1String( "TagRemoteIdResourceRelationTable.tagId" ) );
  
  rv.append( QLatin1String( "TagRemoteIdResourceRelationTable.resourceId" ) );
  
  rv.append( QLatin1String( "TagRemoteIdResourceRelationTable.remoteId" ) );
  
  return rv;
}


QString TagRemoteIdResourceRelation::tagIdColumn()
{
  return QLatin1String( "tagId" );
}

QString TagRemoteIdResourceRelation::tagIdFullColumnName()
{
  return tableName() + QLatin1String( ".tagId" );
}

QString TagRemoteIdResourceRelation::resourceIdColumn()
{
  return QLatin1String( "resourceId" );
}

QString TagRemoteIdResourceRelation::resourceIdFullColumnName()
{
  return tableName() + QLatin1String( ".resourceId" );
}

QString TagRemoteIdResourceRelation::remoteIdColumn()
{
  return QLatin1String( "remoteId" );
}

QString TagRemoteIdResourceRelation::remoteIdFullColumnName()
{
  return tableName() + QLatin1String( ".remoteId" );
}



// count records
int TagRemoteIdResourceRelation::count( const QString &column, const QVariant &value )
{
  return Entity::count<TagRemoteIdResourceRelation>( column, value );
}

// check existence



// result extraction
QVector< TagRemoteIdResourceRelation > TagRemoteIdResourceRelation::extractResult( QSqlQuery & query )
{
  QVector<TagRemoteIdResourceRelation> rv;
  while ( query.next() ) {
    rv.append( TagRemoteIdResourceRelation(
      
        (query.isNull(0)) ?
          qint64() :
          
          query.value( 0 ).value<qint64>()
            ,
        (query.isNull(1)) ?
          qint64() :
          
          query.value( 1 ).value<qint64>()
            ,
        (query.isNull(2)) ?
          QString() :
          
          Utils::variantToString( query.value( 2 ) )
            
    ) );
  }
  return rv;
}

// data retrieval


QVector<TagRemoteIdResourceRelation> TagRemoteIdResourceRelation::retrieveAll()
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<TagRemoteIdResourceRelation>();

  QueryBuilder qb( tableName(), QueryBuilder::Select );
  qb.addColumns( columnNames() );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of all records from table" << tableName()
      << qb.query().lastError().text() << qb.query().lastQuery();
    return QVector<TagRemoteIdResourceRelation>();
  }
  return extractResult( qb.query() );
}

QVector<TagRemoteIdResourceRelation> TagRemoteIdResourceRelation::retrieveFiltered( const QString &key, const QVariant &value )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return QVector<TagRemoteIdResourceRelation>();

  SelectQueryBuilder<TagRemoteIdResourceRelation> qb;
  if ( value.isNull() )
    qb.addValueCondition( key, Query::Is, QVariant() );
  else
    qb.addValueCondition( key, Query::Equals, value );
  if ( !qb.exec() ) {
    akDebug() << "Error during selection of records from table" << tableName()
      << "filtered by" << key << "=" << value
      << qb.query().lastError().text();
    return QVector<TagRemoteIdResourceRelation>();
  }
  return qb.result();
}

// data retrieval for referenced tables
Tag TagRemoteIdResourceRelation::tag() const
{
  return Tag::retrieveById( tagId() );
}

void TagRemoteIdResourceRelation::
    setTag
    ( const Tag &value )
{
  d->tagId = value.id();
  d->tagId_changed = true;
}
Resource TagRemoteIdResourceRelation::resource() const
{
  return Resource::retrieveById( resourceId() );
}

void TagRemoteIdResourceRelation::
    setResource
    ( const Resource &value )
{
  d->resourceId = value.id();
  d->resourceId_changed = true;
}


// data retrieval for inverse referenced tables


#ifndef QT_NO_DEBUG_STREAM
// debug stream operator
QDebug & operator<<( QDebug& d, const TagRemoteIdResourceRelation& entity )
{
  d << "[TagRemoteIdResourceRelation: "
  
    << "tagId = " << entity.tagId()
    << ", "
    << "resourceId = " << entity.resourceId()
    << ", "
    << "remoteId = " << entity.remoteId()
    
    << "]";
  return d;
}
#endif

// inserting new data
bool TagRemoteIdResourceRelation::insert( qint64* insertId )
{
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Insert );
  
    if ( d->tagId_changed  && d->tagId > 0 )
      qb.setColumnValue( tagIdColumn(), this->tagId() );
    
    if ( d->resourceId_changed  && d->resourceId > 0 )
      qb.setColumnValue( resourceIdColumn(), this->resourceId() );
    
    if ( d->remoteId_changed )
      qb.setColumnValue( remoteIdColumn(), this->remoteId() );
    

  if ( !qb.exec() ) {
    akDebug() << "Error during insertion into table" << tableName()
      << qb.query().lastError().text();
    return false;
  }

  setId( qb.insertId() );
  if ( insertId )
    *insertId = id();
  return true;
}

bool TagRemoteIdResourceRelation::hasPendingChanges() const
{
  return false
  
    || d->tagId_changed
  
    || d->resourceId_changed
  
    || d->remoteId_changed
  ;
}

// update existing data
bool TagRemoteIdResourceRelation::update()
{
  invalidateCache();
  QSqlDatabase db = DataStore::self()->database();
  if ( !db.isOpen() )
    return false;

  QueryBuilder qb( tableName(), QueryBuilder::Update );

  
    if ( d->tagId_changed ) {
      
      if ( d->tagId <= 0 )
        qb.setColumnValue( tagIdColumn(), QVariant() );
      else
      
      qb.setColumnValue( tagIdColumn(), this->tagId() );
    }
  
    if ( d->resourceId_changed ) {
      
      if ( d->resourceId <= 0 )
        qb.setColumnValue( resourceIdColumn(), QVariant() );
      else
      
      qb.setColumnValue( resourceIdColumn(), this->resourceId() );
    }
  
    if ( d->remoteId_changed ) {
      
      qb.setColumnValue( remoteIdColumn(), this->remoteId() );
    }
  

  if ( !qb.exec() ) {
    akDebug() << "Error during updating record with id" << id()
             << " in table" << tableName() << qb.query().lastError().text();
    return false;
  }
  return true;
}

// delete records
bool TagRemoteIdResourceRelation::remove( const QString &column, const QVariant &value )
{
  invalidateCompleteCache();
  return Entity::remove<TagRemoteIdResourceRelation>( column, value );
}



// cache stuff
void TagRemoteIdResourceRelation::invalidateCache() const
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::cacheMutex.unlock();
  }
}

void TagRemoteIdResourceRelation::invalidateCompleteCache()
{
  if ( Private::cacheEnabled ) {
    Private::cacheMutex.lock();
    
    Private::cacheMutex.unlock();
  }
}

void TagRemoteIdResourceRelation::enableCache( bool enable )
{
  Private::cacheEnabled = enable;
}



// SQL table information
QString PimItemFlagRelation::tableName()
{
  return QLatin1String( "PimItemFlagRelation" );
}

QString PimItemFlagRelation::leftColumn()
{
  return QLatin1String( "PimItem_id" );
}

QString PimItemFlagRelation::leftFullColumnName()
{
  return tableName() + QLatin1String( "." ) + leftColumn();
}

QString PimItemFlagRelation::rightColumn()
{
  return QLatin1String( "Flag_id" );
}

QString PimItemFlagRelation::rightFullColumnName()
{
  return tableName() + QLatin1String( "." ) + rightColumn();
}


// SQL table information
QString PimItemTagRelation::tableName()
{
  return QLatin1String( "PimItemTagRelation" );
}

QString PimItemTagRelation::leftColumn()
{
  return QLatin1String( "PimItem_id" );
}

QString PimItemTagRelation::leftFullColumnName()
{
  return tableName() + QLatin1String( "." ) + leftColumn();
}

QString PimItemTagRelation::rightColumn()
{
  return QLatin1String( "Tag_id" );
}

QString PimItemTagRelation::rightFullColumnName()
{
  return tableName() + QLatin1String( "." ) + rightColumn();
}


// SQL table information
QString CollectionMimeTypeRelation::tableName()
{
  return QLatin1String( "CollectionMimeTypeRelation" );
}

QString CollectionMimeTypeRelation::leftColumn()
{
  return QLatin1String( "Collection_id" );
}

QString CollectionMimeTypeRelation::leftFullColumnName()
{
  return tableName() + QLatin1String( "." ) + leftColumn();
}

QString CollectionMimeTypeRelation::rightColumn()
{
  return QLatin1String( "MimeType_id" );
}

QString CollectionMimeTypeRelation::rightFullColumnName()
{
  return tableName() + QLatin1String( "." ) + rightColumn();
}


// SQL table information
QString CollectionPimItemRelation::tableName()
{
  return QLatin1String( "CollectionPimItemRelation" );
}

QString CollectionPimItemRelation::leftColumn()
{
  return QLatin1String( "Collection_id" );
}

QString CollectionPimItemRelation::leftFullColumnName()
{
  return tableName() + QLatin1String( "." ) + leftColumn();
}

QString CollectionPimItemRelation::rightColumn()
{
  return QLatin1String( "PimItem_id" );
}

QString CollectionPimItemRelation::rightFullColumnName()
{
  return tableName() + QLatin1String( "." ) + rightColumn();
}


QVector<QString> Akonadi::Server::allDatabaseTables()
{
  static QVector<QString> allTables = QVector<QString>()
  
    << QLatin1String( "SchemaVersionTable" )
  
    << QLatin1String( "ResourceTable" )
  
    << QLatin1String( "CollectionTable" )
  
    << QLatin1String( "MimeTypeTable" )
  
    << QLatin1String( "PimItemTable" )
  
    << QLatin1String( "FlagTable" )
  
    << QLatin1String( "PartTypeTable" )
  
    << QLatin1String( "PartTable" )
  
    << QLatin1String( "CollectionAttributeTable" )
  
    << QLatin1String( "TagTypeTable" )
  
    << QLatin1String( "TagTable" )
  
    << QLatin1String( "TagAttributeTable" )
  
    << QLatin1String( "TagRemoteIdResourceRelationTable" )
  
    << QLatin1String( "PimItemFlagRelation" )
  
    << QLatin1String( "PimItemTagRelation" )
  
    << QLatin1String( "CollectionMimeTypeRelation" )
  
    << QLatin1String( "CollectionPimItemRelation" )
  
  ;
  return allTables;
}

