/* * this method saves the attribute together with the host string that * defines the type of object that this attribute is associated to (like * position or document) and the hosts database id. */ void AttributeMap::save( dbID id ) { checkHost(); QSqlQuery attribQuery; attribQuery.prepare( "SELECT id, valueIsList FROM attributes WHERE hostObject=:host AND hostId=:hostId AND name=:name" ); attribQuery.bindValue( ":host", mHost ); attribQuery.bindValue( ":hostId", id.toString() ); Iterator it; for ( it = begin(); it != end(); ++it ) { Attribute att = it.value(); kDebug() << ">> oo- saving attribute with name " << it.key() << " for " << id.toString() << " att-name: " << att.name(); attribQuery.bindValue( ":name", att.name() ); attribQuery.exec(); QString attribId; if ( attribQuery.next() ) { // the attrib exists. Check the values attribId = attribQuery.value(0).toString(); // the id if ( att.value().isNull() || att.mDelete ) { // the value is empty. the existing entry needs to be dropped dbDeleteAttribute( attribId ); return; } } else { // the attrib does not yet exist. Create if att value is not null. if ( att.value().isNull() ) { kDebug() << "oo- skip writing of attribute, value is empty"; } else { kDebug() << "oo- writing of attribute name " << att.name(); QSqlQuery insQuery; insQuery.prepare( "INSERT INTO attributes (hostObject, hostId, name, valueIsList, relationTable, " "relationIDColumn, relationStringColumn) " "VALUES (:host, :hostId, :name, :valueIsList, :relTable, :relIDCol, :relStringCol )" ); insQuery.bindValue( ":host", mHost ); insQuery.bindValue( ":hostId", id.toString() ); insQuery.bindValue( ":name", att.name() ); insQuery.bindValue( ":valueIsList", att.listValue() ); // Write the relation table info. These remain empty for non related attributes. insQuery.bindValue( ":relTable", att.mTable ); insQuery.bindValue( ":relIDCol", att.mIdCol ); insQuery.bindValue( ":relStringCol", att.mStringCol ); insQuery.exec(); dbID attId = KraftDB::self()->getLastInsertID(); attribId = attId.toString(); } } // store the id to be able to drop not longer existent values kDebug() << "adding attribute id " << attribId << " for attribute " << att.name(); // now there is a valid entry in the attribute table. Check the values. QSqlQuery valueQuery( "SELECT id, value FROM attributeValues WHERE attributeId=" + attribId ); typedef QMap<QString, QString> ValueMap; ValueMap valueMap; while ( valueQuery.next() ) { QString idStr = valueQuery.value( 0 ).toString(); // id QString valStr = valueQuery.value( 1 ).toString(); // value valueMap[valStr] = idStr; } // create a stringlist with the current values of the attribute if ( att.listValue() ) { QStringList newValues; newValues = att.mValue.toStringList(); kDebug() << "new values are: " << newValues.join( ", " ); if ( newValues.empty() ) { // delete the entire attribute. dbDeleteValue( attribId ); // deletes all values dbDeleteAttribute( attribId ); valueMap.clear(); } else { // we really have new values QSqlQuery insValue; insValue.prepare( "INSERT INTO attributeValues (attributeId, value) VALUES (:attribId, :val)" ); insValue.bindValue( ":attribId", attribId ); // loop over all existing new values of the attribute. for ( QStringList::Iterator valIt = newValues.begin(); valIt != newValues.end(); ++valIt ) { QString curValue = *valIt; if ( valueMap.contains( curValue ) ) { // the valueMap is already saved. remove it from the valueMap string kDebug() << "Value " << curValue << " is already present with id " << valueMap[curValue]; valueMap.remove( curValue ); } else { // the value is not yet there, insert it. insValue.bindValue( ":val", curValue ); insValue.exec(); } } } } else { // only a single entry for the attribte, update if needed. QString newValue = att.mValue.toString(); // access the attribute object directly to get the numeric kDebug() << "NEW value String: " << newValue; // value in case the attribute is bound to a relation table if ( newValue.isEmpty() ) { // delete the entire attribute dbDeleteValue( attribId ); // deletes all values dbDeleteAttribute( attribId ); valueMap.clear(); } else { if ( valueMap.empty() ) { // there is no entry yet that could be updated. QSqlQuery insertQuery; insertQuery.prepare( "INSERT INTO attributeValues (attributeId, value ) VALUES (:id, :val)" ); insertQuery.bindValue( ":id", attribId ); insertQuery.bindValue( ":val", newValue ); insertQuery.exec(); kDebug() << "insert new attrib value for non list: " << newValue; } else { QString oldValue = valueMap.begin().key(); QString id = valueMap.begin().value(); if ( newValue != oldValue ) { kDebug() << "Updating " << id << " from " << oldValue << " to " << newValue; QSqlQuery updateQuery; updateQuery.prepare( "UPDATE attributeValues SET value=:val WHERE id=:id" ); updateQuery.bindValue( ":val", newValue ); updateQuery.bindValue( ":id", id ); kDebug() << "do the update!"; updateQuery.exec(); } valueMap.remove( oldValue ); } } } // remove all still existing entries in the valueMap because they point to values which are // in the db but were deleted from the attribute if ( ! valueMap.isEmpty() ) { ValueMap::Iterator mapIt; for ( mapIt = valueMap.begin(); mapIt != valueMap.end(); ++mapIt ) { QString valId = mapIt.value(); dbDeleteValue( attribId, valId ); } } } }