Added a getmulti(SelectionMaskPtr) to SavableManager.
[UnsignedByte.git] / src / DAL / SavableManager.cpp
blob0bd2dbd15707dc20d54e23ef3044f185e3861569
1 /***************************************************************************
2 * Copyright (C) 2008 by Sverre Rabbelier *
3 * sverre@rabbelier.nl *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 3 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
21 #include "SavableManager.h"
22 #include "SavableManagers.h"
23 #include "FieldValue.h"
24 #include "FieldValues.h"
25 #include "KeyValue.h"
26 #include "Keys.h"
27 #include "KeyImpl.h"
28 #include "FieldImpl.h"
29 #include "TableImpl.h"
30 #include "SqliteMgr.h"
31 #include "StringUtilities.h"
32 #include "SelectionMask.h"
33 #include "Relation.h"
34 #include "Join.h"
36 ByKeyCache SavableManager::ms_byKeyCache;
37 ByValueCache SavableManager::ms_byValueCache;
39 SavableManager::SavableManager(TableImplPtr table) :
40 m_table(table),
41 m_newentry(true),
42 m_locked(false)
44 Assert(table);
46 for(FieldImplVector::const_iterator it = table->begin(); it != table->end(); it++)
48 FieldImplPtr field = *it;
49 Assert(field);
51 m_fields[it->get()] = field->newValue();
55 SavableManager::~SavableManager()
60 SavableManagersPtr SavableManager::getmulti(FieldValuesPtr values) // static
62 Assert(values);
64 Joins joins;
65 return getmulti(values, joins);
68 SavableManagersPtr SavableManager::getmulti(FieldValuesPtr values, const Joins& joins) // static
70 Assert(values);
72 TableImplPtr table = values->getTable();
73 Assert(table);
75 SelectionMaskPtr mask(new SelectionMask(table));
77 for(ValueMap::const_iterator it = values->begin(); it != values->end(); it++)
79 ValuePtr value = it->second;
80 mask->addField(value);
83 for(Joins::const_iterator it = joins.begin(); it != joins.end(); it++)
85 JoinPtr join = *it;
86 mask->addJoin(join);
89 return getmulti(mask);
92 SavableManagersPtr SavableManager::getmulti(SelectionMaskPtr mask) // static
94 Assert(mask);
96 SqliteMgr::Get()->doSelectMulti(mask.get());
97 return mask->getResult();
100 SavableManagerPtr SavableManager::getnew(TableImplPtr table) // static
102 Assert(table);
104 SavableManagerPtr result(new SavableManager(table));
105 return result;
108 SavableManagerPtr SavableManager::bykey(KeyValuePtr key) // static
110 Assert(key);
112 TableImplPtr table = key->getTable();
113 KeysPtr keys(new Keys(table));
114 keys->addKey(key);
115 return bykeys(keys);
118 SavableManagerPtr SavableManager::bykeys(KeysPtr keys) // static
120 Assert(keys);
122 KeyFieldMap map = constructMap(keys);
124 if(ms_byKeyCache.find(map) == ms_byKeyCache.end())
126 SavableManagerPtr result = getnew(keys->getTable());
128 bool locked = result->lock(); // new object, should always be unlocked
129 Assert(locked);
131 /// Begin locked section
132 result->setKeys(keys);
133 SqliteMgr::Get()->doSelect(result.get());
134 doFullCache(result);
135 result->cleanup();
136 /// End locked section
138 result->unlock();
141 SavableManagerPtr result = ms_byKeyCache[map];
142 Assert(result);
144 return result;
147 SavableManagerPtr SavableManager::byvalue(ValuePtr value) // static
149 Assert(value);
151 FieldImplPtr field = value->getField();
152 Assert(field);
153 Assert(field->isLookup());
155 TextFieldPair pair = constructPair(value);
157 if(ms_byValueCache.find(pair) == ms_byValueCache.end())
159 SavableManagerPtr result = getnew(value->getTable());
161 bool locked = result->lock(); // new object, should always be unlocked
162 Assert(locked);
164 /// Begin locked section
165 result->m_lookupvalue = value;
166 SqliteMgr::Get()->doLookup(result.get(), value->getField());
167 doFullCache(result);
168 result->cleanup();
169 /// End locked section
171 result->unlock();
174 SavableManagerPtr result = ms_byValueCache[pair];
175 Assert(result);
177 return result;
180 KeysPtr SavableManager::lookupvalue(ValuePtr value) // static
182 Assert(value);
184 SavableManagerPtr result = byvalue(value);
185 KeysPtr keys = result->getKeys();
186 return keys;
190 size_t SavableManager::count(SelectionMaskPtr mask)
192 Assert(mask);
194 SqliteMgr::Get()->doCount(mask.get());
195 return mask->getCount();
198 size_t SavableManager::count(KeysPtr keys)
200 Assert(keys);
201 Assert(keys->size() == keys->getTable()->primarykeysize());
203 TableImplPtr table = keys->getTable();
204 Assert(table);
206 SelectionMaskPtr mask(new SelectionMask(table));
208 for(KeyImplMap::const_iterator it = keys->begin(); it != keys->end(); it++)
210 KeyValuePtr key = it->second;
211 Assert(key);
213 mask->addField(key);
216 return count(mask);
219 void SavableManager::doFullCache(SavableManagerPtr manager) // static
221 Assert(manager);
223 Assert(manager->primaryKeySize() == manager->getTable()->primarykeysize());
225 KeyFieldMap map = constructMap(manager);
226 ms_byKeyCache[map] = manager;
228 for(FieldImplVector::const_iterator it = manager->getTable()->begin(); it != manager->getTable()->end(); it++)
230 FieldImplPtr field = *it;
231 Assert(field);
233 if(!field->isLookup())
234 continue;
236 ValuePtr value = manager->getValue(field);
237 Assert(value);
239 TextFieldPair pair = constructPair(value);
241 // Don't allow overwriting a previous value, unless it pointed to us.
242 Assert((ms_byValueCache.find(pair) == ms_byValueCache.end()) || (ms_byValueCache[pair] == manager));
243 ms_byValueCache[pair] = manager;
247 void SavableManager::doUncache(SavableManagerPtr manager) // static
249 Assert(manager);
251 for(FieldImplVector::const_iterator it = manager->getTable()->begin(); it != manager->getTable()->end(); it++)
253 FieldImplPtr field = *it;
254 Assert(field);
256 if(!field->isLookup())
257 continue;
259 FieldImpl* fieldptr = field.get();
260 Assert(fieldptr);
262 FieldValuePtr value = manager->m_orig[fieldptr];
264 // Check if it was a new value
265 if(!value)
266 continue;
268 TextFieldPair pair = constructPair(value);
270 // Assert that any previous values reference us
271 Assert((ms_byValueCache.find(pair) == ms_byValueCache.end()) || (ms_byValueCache[pair] == manager));
272 ms_byValueCache.erase(pair);
276 void SavableManager::doRecache(SavableManagerPtr manager)
278 doUncache(manager);
279 doFullCache(manager);
282 KeyFieldMap SavableManager::constructMap(KeysPtr keys) // static
284 KeyFieldMap result;
285 for(KeyImplMap::const_iterator it = keys->begin(); it != keys->end(); it++)
286 result[it->first] = it->second->getIntegerValue();
288 return result;
291 KeyFieldMap SavableManager::constructMap(SavableManagerPtr manager) // static
293 KeyFieldMap result;
295 for(FieldImplVector::const_iterator it = manager->getTable()->begin(); it != manager->getTable()->end(); it++)
297 FieldImplPtr field = *it;
298 Assert(field);
300 if(!field->isPrimaryKey())
301 continue;
303 FieldValuePtr fieldvalue = manager->getValue(field);
304 Assert(fieldvalue);
306 KeyValuePtr key = boost::static_pointer_cast<KeyValue>(fieldvalue);
307 Assert(key);
309 KeyImplPtr keyimpl = key->getKeyImpl();
310 Assert(keyimpl);
312 result[keyimpl.get()] = key->getIntegerValue();
315 return result;
318 TextFieldPair SavableManager::constructPair(ValuePtr value) // static
320 TextFieldPair result;
321 FieldImplPtr field = value->getField();
323 result.first = field.get();
324 if(field->isText())
325 result.second = value->getStringValue();
326 else
327 result.second = String::Get()->fromInt(value->getIntegerValue());
329 return result;
332 std::string SavableManager::fromMap(const KeyFieldMap& map) // static
334 Strings result;
335 std::string tablename;
337 for(std::map<KeyImpl*, value_type>::const_iterator it = map.begin(); it != map.end(); it++)
339 KeyImpl* key = it->first;
340 value_type value = it->second;
342 TableImplPtr table = key->getTable();
343 Assert(table);
345 tablename = table->getName();
347 std::string line = key->getName();
348 line.append(": ");
349 line.append(String::Get()->fromInt(value));
351 result.push_back(line);
354 std::string name("Keys from table ");
355 name.append(tablename);
357 return String::Get()->box(result, name);
360 void SavableManager::erase()
362 Assert(m_locked);
364 if(m_newentry)
365 return;
367 SqliteMgr::Get()->doErase(this);
368 doUncache(shared_from_this());
371 void SavableManager::save()
373 Assert(m_locked);
375 if(m_newentry)
377 SqliteMgr::Get()->doInsert(this);
378 doFullCache(shared_from_this());
379 m_newentry = false;
382 if(m_orig.size() > 0)
384 SqliteMgr::Get()->doUpdate(this);
385 doRecache(shared_from_this());
386 cleanup();
390 void SavableManager::discard()
392 Assert(m_locked);
394 SqliteMgr::Get()->doSelect(this);
395 cleanup();
398 bool SavableManager::exists() const
400 if(m_newentry)
401 return false;
403 return true;
406 bool SavableManager::lock()
408 if(m_locked)
409 return false;
411 m_locked = true;
412 return true;
415 void SavableManager::unlock()
417 Assert(m_locked);
419 m_locked = false;
422 void SavableManager::bindKeys(sqlite3* db, sqlite3_stmt* stmt, const int startpos) const
424 Assert(db);
425 Assert(stmt);
427 int pos = startpos;
428 int rc = 0;
429 for(FieldImplVector::const_iterator it = m_table->begin(); it != m_table->end(); it++)
431 FieldImplPtr field = *it;
432 Assert(field);
434 if(!field->isPrimaryKey())
435 continue;
437 FieldValuePtr fieldvalue = getValue(field);
438 Assert(fieldvalue);
440 value_type value = fieldvalue->getIntegerValue();
442 rc = sqlite3_bind_int64(stmt, pos, value);
444 if(rc != SQLITE_OK)
445 throw SqliteError(db);
447 pos++;
451 void SavableManager::bindFields(sqlite3* db, sqlite3_stmt* stmt, const int startpos) const
453 Assert(db);
454 Assert(stmt);
456 int pos = startpos;
457 int rc = 0;
458 for(FieldImplVector::const_iterator it = m_table->begin(); it != m_table->end(); it++)
460 FieldImplPtr field = *it;
461 Assert(field);
463 if(field->isPrimaryKey())
464 continue;
466 if(field->isText())
468 FieldValuePtr value = getValue(field);
469 std::string stringvalue = value->getStringValue();
470 rc = sqlite3_bind_text(stmt, pos, stringvalue.c_str(), stringvalue.size(), SQLITE_TRANSIENT);
472 else
474 FieldValuePtr value = getValue(field);
475 value_type integervalue = value->getIntegerValue();
476 rc = sqlite3_bind_int64(stmt, pos, integervalue);
479 if(rc != SQLITE_OK)
480 throw SqliteError(db);
481 pos++;
485 void SavableManager::bindUpdate(sqlite3* db, sqlite3_stmt* stmt) const
487 Assert(db);
488 Assert(stmt);
490 bindFields(db, stmt);
491 bindKeys(db, stmt, m_fields.size() - primaryKeySize() + 1);
494 void SavableManager::bindLookup(sqlite3* db, sqlite3_stmt* stmt) const
496 Assert(db);
497 Assert(stmt);
499 int rc = 0;
500 if(m_lookupvalue->getField()->isText())
501 rc = sqlite3_bind_text(stmt, 1, m_lookupvalue->getStringValue().c_str(), m_lookupvalue->getStringValue().size(), SQLITE_TRANSIENT);
502 else
503 rc = sqlite3_bind_int64(stmt, 1, m_lookupvalue->getIntegerValue());
505 if(rc != SQLITE_OK)
506 throw SqliteError(db);
509 void SavableManager::parseInsert(sqlite3* db)
511 Assert(m_locked);
512 Assert(db);
513 Assert(m_table->primarykeysize() == 1);
515 FieldImplPtr field = m_table->firstkey();
516 Assert(field);
518 value_type value = sqlite3_last_insert_rowid(db);
520 FieldValuePtr key = field->newValue();
521 Assert(key->isKey());
523 key->setIntegerValue(value);
525 setValue(key);
528 void SavableManager::parseSelect(sqlite3_stmt* stmt, const int startpos)
530 Assert(m_locked);
531 Assert(stmt);
533 int pos = startpos;
534 const unsigned char * text;
535 for(FieldImplVector::const_iterator it = m_table->begin(); it != m_table->end(); it++)
537 FieldImplPtr field = *it;
538 Assert(field);
540 if(field->isPrimaryKey())
541 continue;
543 if(field->isText())
545 text = sqlite3_column_text(stmt, pos);
546 if(text != 0)
548 std::string value = std::string((const char *)text);
550 FieldValuePtr fieldvalue = getValue(field);
551 getValue(field)->setTextValue(value);
554 else
556 value_type value = sqlite3_column_int64(stmt, pos);
557 FieldValuePtr fieldvalue = getValue(field);
558 getValue(field)->setIntegerValue(value);
561 pos++;
564 m_newentry = false;
567 void SavableManager::parseLookup(sqlite3_stmt* stmt)
569 Assert(m_locked);
570 Assert(stmt);
572 int pos = 0;
573 for(FieldImplVector::const_iterator it = m_table->begin(); it != m_table->end(); it++)
575 FieldImplPtr field = *it;
576 Assert(field);
578 if(!field->isPrimaryKey())
579 continue;
581 KeyImplPtr key = boost::static_pointer_cast<KeyImpl>(field);
582 Assert(key);
584 setValue(key, sqlite3_column_int64(stmt, pos));
585 pos++;
589 TableImplPtr SavableManager::getTable() const
591 return m_table;
594 size_t SavableManager::primaryKeySize() const
596 size_t keysize = 0;
598 for(FieldImplVector::const_iterator it = m_table->begin(); it != m_table->end(); it++)
600 FieldImplPtr field = *it;
601 Assert(field);
603 if(!field->isPrimaryKey())
604 continue;
606 keysize++;
609 return keysize;
612 KeysPtr SavableManager::getKeys() const
614 KeysPtr result(new Keys(m_table));
616 for(FieldImplVector::const_iterator it = m_table->begin(); it != m_table->end(); it++)
618 FieldImplPtr field = *it;
619 Assert(field);
621 if(!field->isPrimaryKey())
622 continue;
624 FieldValuePtr value = getValue(field);
625 Assert(value);
627 KeyValuePtr key = boost::static_pointer_cast<KeyValue>(value);
628 Assert(key);
630 Assert(key->isKey());
631 result->addKey(key);
634 return result;
637 ValuePtr SavableManager::getValue(FieldImplPtr field) const
639 Assert(field);
641 FieldValueMap::const_iterator it = m_fields.find(field.get());
642 Assert(it != m_fields.end());
644 return it->second;
647 std::string SavableManager::getDiff() const
649 std::vector<std::string> result;
651 for(FieldImplVector::const_iterator it = m_table->begin(); it != m_table->end(); it++)
653 FieldImplPtr field = *it;
654 Assert(field);
656 // Check if the field has been changed
657 FieldValueMap::const_iterator it = m_orig.find(field.get());
658 if(it == m_orig.end())
659 continue;
661 // Retreive the original value.
662 FieldValuePtr origValue = it->second;
663 Assert(origValue);
665 // Retreive the current value.
666 FieldValuePtr currentValue = getValue(field);
667 Assert(currentValue);
669 std::string line = "Changed field '";
670 if(field->isKey() && !field->isPrimaryKey())
671 line.append(field->getName().substr(2));
672 else
673 line.append(field->getName());
674 line.append("' from '");
676 if(field->isText())
677 line.append(origValue->getStringValue());
678 else
679 line.append(String::Get()->fromInt(origValue->getIntegerValue()));
681 line.append("' to '");
683 if(field->isText())
684 line.append(currentValue->getStringValue());
685 else
686 line.append(String::Get()->fromInt(currentValue->getIntegerValue()));
688 line.append("'.");
690 result.push_back(line);
693 return String::Get()->unlines(result, "\n", 0);
696 bool SavableManager::isDirty() const
698 return m_orig.size() > 0;
701 void SavableManager::setKeys(KeysPtr keys)
703 Assert(m_locked);
704 Assert(keys);
705 Assert(keys->size() == m_table->primarykeysize());
707 for(KeyImplMap::const_iterator it = keys->begin(); it != keys->end(); it++) {
708 Assert(it->first->getTable() == m_table);
709 setValue(it->second);
713 void SavableManager::setValue(FieldValuePtr value)
715 Assert(m_locked);
716 Assert(value);
717 Assert(value->getTable() == m_table);
719 FieldImpl* field = value->getField().get();
720 Assert(field);
722 Assert(m_fields.find(field) != m_fields.end());
724 // Store the original value in m_orig
725 if(m_orig.find(field) == m_orig.end())
726 m_orig[field] = m_fields[field];
728 m_fields[field] = value;
731 void SavableManager::setValue(FieldImplPtr field, cstring value) // delegator
733 FieldValuePtr fieldvalue(new FieldValue(field, value));
734 setValue(fieldvalue);
737 void SavableManager::setValue(FieldImplPtr field, value_type value) // delegator
739 FieldValuePtr fieldvalue(new FieldValue(field, value));
740 setValue(fieldvalue);
743 void SavableManager::setValue(KeyImplPtr field, value_type value) // delegator
745 KeyValuePtr fieldvalue(new KeyValue(field, value));
746 setValue(fieldvalue);
749 void SavableManager::cleanup()
751 Assert(m_locked);
753 m_orig.clear();
756 std::string SavableManager::toString()
758 std::string name = getTable()->getName();
759 name.append(" <");
760 name.append(getKeys()->toString());
761 name.append(">");
763 Strings fieldlist;
765 for(FieldImplVector::const_iterator it = m_table->begin(); it != m_table->end(); it++)
767 FieldImplPtr field = *it;
768 Assert(field);
770 ValuePtr value = getValue(field);
771 Assert(value);
773 std::string line = field->getName();
774 line.append(": ");
776 if(field->isText())
777 line.append(value->getStringValue());
778 else
779 line.append(String::Get()->fromInt(value->getIntegerValue()));
781 fieldlist.push_back(line);
784 return String::Get()->box(fieldlist, name);
787 Strings SavableManager::fieldList() const
789 Strings result;
791 for(FieldImplVector::const_iterator it = m_table->begin(); it != m_table->end(); it++)
793 FieldImplPtr field = *it;
794 Assert(field);
796 ValuePtr value = getValue(field);
798 if(field->isText()) {
799 result.push_back(value->getStringValue());
801 else
803 // TODO lookup foreign keys
805 if(field->isKey())
807 int keyvalue = value->getIntegerValue();
809 KeyImplPtr keyimpl = boost::static_pointer_cast<KeyImpl>(field);
810 KeyValuePtr key(new KeyValue(keyimpl, keyvalue));
812 try {
813 SavableManagerPtr manager = SavableManager::bykey(key);
814 } catch(RowNotFoundException& e) {
815 // TODO handle
818 // result.push_back(manager->getfield(manager->getIdentifyingField())->getStringValue());
819 // TODO
820 // continue;
824 result.push_back(String::Get()->fromInt(value->getIntegerValue()));
828 return result;