1 /***************************************************************************
2 * Copyright (C) 2008 by Sverre Rabbelier *
3 * sverre@rabbelier.nl *
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. *
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. *
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"
28 #include "FieldImpl.h"
29 #include "TableImpl.h"
30 #include "SqliteMgr.h"
31 #include "StringUtilities.h"
32 #include "SelectionMask.h"
36 ByKeyCache
SavableManager::ms_byKeyCache
;
37 ByValueCache
SavableManager::ms_byValueCache
;
39 SavableManager::SavableManager(TableImplPtr table
) :
46 for(FieldImplVector::const_iterator it
= table
->begin(); it
!= table
->end(); it
++)
48 FieldImplPtr field
= *it
;
51 m_fields
[it
->get()] = field
->newValue();
55 SavableManager::~SavableManager()
60 SavableManagersPtr
SavableManager::getmulti(FieldValuesPtr values
) // static
65 return getmulti(values
, joins
);
68 SavableManagersPtr
SavableManager::getmulti(FieldValuesPtr values
, const Joins
& joins
) // static
72 TableImplPtr table
= values
->getTable();
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
++)
89 return getmulti(mask
);
92 SavableManagersPtr
SavableManager::getmulti(SelectionMaskPtr mask
) // static
96 SqliteMgr::Get()->doSelectMulti(mask
.get());
97 return mask
->getResult();
100 SavableManagerPtr
SavableManager::getnew(TableImplPtr table
) // static
104 SavableManagerPtr
result(new SavableManager(table
));
108 SavableManagerPtr
SavableManager::bykey(KeyValuePtr key
) // static
112 TableImplPtr table
= key
->getTable();
113 KeysPtr
keys(new Keys(table
));
118 SavableManagerPtr
SavableManager::bykeys(KeysPtr keys
) // static
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
131 /// Begin locked section
132 result
->setKeys(keys
);
133 SqliteMgr::Get()->doSelect(result
.get());
136 /// End locked section
141 SavableManagerPtr result
= ms_byKeyCache
[map
];
147 SavableManagerPtr
SavableManager::byvalue(ValuePtr value
) // static
151 FieldImplPtr field
= value
->getField();
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
164 /// Begin locked section
165 result
->m_lookupvalue
= value
;
166 SqliteMgr::Get()->doLookup(result
.get(), value
->getField());
169 /// End locked section
174 SavableManagerPtr result
= ms_byValueCache
[pair
];
180 KeysPtr
SavableManager::lookupvalue(ValuePtr value
) // static
184 SavableManagerPtr result
= byvalue(value
);
185 KeysPtr keys
= result
->getKeys();
190 size_t SavableManager::count(SelectionMaskPtr mask
)
194 SqliteMgr::Get()->doCount(mask
.get());
195 return mask
->getCount();
198 size_t SavableManager::count(KeysPtr keys
)
201 Assert(keys
->size() == keys
->getTable()->primarykeysize());
203 TableImplPtr table
= keys
->getTable();
206 SelectionMaskPtr
mask(new SelectionMask(table
));
208 for(KeyImplMap::const_iterator it
= keys
->begin(); it
!= keys
->end(); it
++)
210 KeyValuePtr key
= it
->second
;
219 void SavableManager::doFullCache(SavableManagerPtr manager
) // static
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
;
233 if(!field
->isLookup())
236 ValuePtr value
= manager
->getValue(field
);
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
251 for(FieldImplVector::const_iterator it
= manager
->getTable()->begin(); it
!= manager
->getTable()->end(); it
++)
253 FieldImplPtr field
= *it
;
256 if(!field
->isLookup())
259 FieldImpl
* fieldptr
= field
.get();
262 FieldValuePtr value
= manager
->m_orig
[fieldptr
];
264 // Check if it was a new value
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
)
279 doFullCache(manager
);
282 KeyFieldMap
SavableManager::constructMap(KeysPtr keys
) // static
285 for(KeyImplMap::const_iterator it
= keys
->begin(); it
!= keys
->end(); it
++)
286 result
[it
->first
] = it
->second
->getIntegerValue();
291 KeyFieldMap
SavableManager::constructMap(SavableManagerPtr manager
) // static
295 for(FieldImplVector::const_iterator it
= manager
->getTable()->begin(); it
!= manager
->getTable()->end(); it
++)
297 FieldImplPtr field
= *it
;
300 if(!field
->isPrimaryKey())
303 FieldValuePtr fieldvalue
= manager
->getValue(field
);
306 KeyValuePtr key
= boost::static_pointer_cast
<KeyValue
>(fieldvalue
);
309 KeyImplPtr keyimpl
= key
->getKeyImpl();
312 result
[keyimpl
.get()] = key
->getIntegerValue();
318 TextFieldPair
SavableManager::constructPair(ValuePtr value
) // static
320 TextFieldPair result
;
321 FieldImplPtr field
= value
->getField();
323 result
.first
= field
.get();
325 result
.second
= value
->getStringValue();
327 result
.second
= String::Get()->fromInt(value
->getIntegerValue());
332 std::string
SavableManager::fromMap(const KeyFieldMap
& map
) // static
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();
345 tablename
= table
->getName();
347 std::string line
= key
->getName();
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()
367 SqliteMgr::Get()->doErase(this);
368 doUncache(shared_from_this());
371 void SavableManager::save()
377 SqliteMgr::Get()->doInsert(this);
378 doFullCache(shared_from_this());
382 if(m_orig
.size() > 0)
384 SqliteMgr::Get()->doUpdate(this);
385 doRecache(shared_from_this());
390 void SavableManager::discard()
394 SqliteMgr::Get()->doSelect(this);
398 bool SavableManager::exists() const
406 bool SavableManager::lock()
415 void SavableManager::unlock()
422 void SavableManager::bindKeys(sqlite3
* db
, sqlite3_stmt
* stmt
, const int startpos
) const
429 for(FieldImplVector::const_iterator it
= m_table
->begin(); it
!= m_table
->end(); it
++)
431 FieldImplPtr field
= *it
;
434 if(!field
->isPrimaryKey())
437 FieldValuePtr fieldvalue
= getValue(field
);
440 value_type value
= fieldvalue
->getIntegerValue();
442 rc
= sqlite3_bind_int64(stmt
, pos
, value
);
445 throw SqliteError(db
);
451 void SavableManager::bindFields(sqlite3
* db
, sqlite3_stmt
* stmt
, const int startpos
) const
458 for(FieldImplVector::const_iterator it
= m_table
->begin(); it
!= m_table
->end(); it
++)
460 FieldImplPtr field
= *it
;
463 if(field
->isPrimaryKey())
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
);
474 FieldValuePtr value
= getValue(field
);
475 value_type integervalue
= value
->getIntegerValue();
476 rc
= sqlite3_bind_int64(stmt
, pos
, integervalue
);
480 throw SqliteError(db
);
485 void SavableManager::bindUpdate(sqlite3
* db
, sqlite3_stmt
* stmt
) const
490 bindFields(db
, stmt
);
491 bindKeys(db
, stmt
, m_fields
.size() - primaryKeySize() + 1);
494 void SavableManager::bindLookup(sqlite3
* db
, sqlite3_stmt
* stmt
) const
500 if(m_lookupvalue
->getField()->isText())
501 rc
= sqlite3_bind_text(stmt
, 1, m_lookupvalue
->getStringValue().c_str(), m_lookupvalue
->getStringValue().size(), SQLITE_TRANSIENT
);
503 rc
= sqlite3_bind_int64(stmt
, 1, m_lookupvalue
->getIntegerValue());
506 throw SqliteError(db
);
509 void SavableManager::parseInsert(sqlite3
* db
)
513 Assert(m_table
->primarykeysize() == 1);
515 FieldImplPtr field
= m_table
->firstkey();
518 value_type value
= sqlite3_last_insert_rowid(db
);
520 FieldValuePtr key
= field
->newValue();
521 Assert(key
->isKey());
523 key
->setIntegerValue(value
);
528 void SavableManager::parseSelect(sqlite3_stmt
* stmt
, const int startpos
)
534 const unsigned char * text
;
535 for(FieldImplVector::const_iterator it
= m_table
->begin(); it
!= m_table
->end(); it
++)
537 FieldImplPtr field
= *it
;
540 if(field
->isPrimaryKey())
545 text
= sqlite3_column_text(stmt
, pos
);
548 std::string value
= std::string((const char *)text
);
550 FieldValuePtr fieldvalue
= getValue(field
);
551 getValue(field
)->setTextValue(value
);
556 value_type value
= sqlite3_column_int64(stmt
, pos
);
557 FieldValuePtr fieldvalue
= getValue(field
);
558 getValue(field
)->setIntegerValue(value
);
567 void SavableManager::parseLookup(sqlite3_stmt
* stmt
)
573 for(FieldImplVector::const_iterator it
= m_table
->begin(); it
!= m_table
->end(); it
++)
575 FieldImplPtr field
= *it
;
578 if(!field
->isPrimaryKey())
581 KeyImplPtr key
= boost::static_pointer_cast
<KeyImpl
>(field
);
584 setValue(key
, sqlite3_column_int64(stmt
, pos
));
589 TableImplPtr
SavableManager::getTable() const
594 size_t SavableManager::primaryKeySize() const
598 for(FieldImplVector::const_iterator it
= m_table
->begin(); it
!= m_table
->end(); it
++)
600 FieldImplPtr field
= *it
;
603 if(!field
->isPrimaryKey())
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
;
621 if(!field
->isPrimaryKey())
624 FieldValuePtr value
= getValue(field
);
627 KeyValuePtr key
= boost::static_pointer_cast
<KeyValue
>(value
);
630 Assert(key
->isKey());
637 ValuePtr
SavableManager::getValue(FieldImplPtr field
) const
641 FieldValueMap::const_iterator it
= m_fields
.find(field
.get());
642 Assert(it
!= m_fields
.end());
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
;
656 // Check if the field has been changed
657 FieldValueMap::const_iterator it
= m_orig
.find(field
.get());
658 if(it
== m_orig
.end())
661 // Retreive the original value.
662 FieldValuePtr origValue
= it
->second
;
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));
673 line
.append(field
->getName());
674 line
.append("' from '");
677 line
.append(origValue
->getStringValue());
679 line
.append(String::Get()->fromInt(origValue
->getIntegerValue()));
681 line
.append("' to '");
684 line
.append(currentValue
->getStringValue());
686 line
.append(String::Get()->fromInt(currentValue
->getIntegerValue()));
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
)
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
)
717 Assert(value
->getTable() == m_table
);
719 FieldImpl
* field
= value
->getField().get();
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()
756 std::string
SavableManager::toString()
758 std::string name
= getTable()->getName();
760 name
.append(getKeys()->toString());
765 for(FieldImplVector::const_iterator it
= m_table
->begin(); it
!= m_table
->end(); it
++)
767 FieldImplPtr field
= *it
;
770 ValuePtr value
= getValue(field
);
773 std::string line
= field
->getName();
777 line
.append(value
->getStringValue());
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
791 for(FieldImplVector::const_iterator it
= m_table
->begin(); it
!= m_table
->end(); it
++)
793 FieldImplPtr field
= *it
;
796 ValuePtr value
= getValue(field
);
798 if(field
->isText()) {
799 result
.push_back(value
->getStringValue());
803 // TODO lookup foreign keys
807 int keyvalue = value->getIntegerValue();
809 KeyImplPtr keyimpl = boost::static_pointer_cast<KeyImpl>(field);
810 KeyValuePtr key(new KeyValue(keyimpl, keyvalue));
813 SavableManagerPtr manager = SavableManager::bykey(key);
814 } catch(RowNotFoundException& e) {
818 // result.push_back(manager->getfield(manager->getIdentifyingField())->getStringValue());
824 result
.push_back(String::Get()->fromInt(value
->getIntegerValue()));