KDb

KDbTableSchema.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2003 Joseph Wenninger <jowenn@kde.org>
3 Copyright (C) 2003-2016 Jarosław Staniek <staniek@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library 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 GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19*/
20
21#include "KDbTableSchema.h"
22#include "KDbDriver.h"
23#include "KDbConnection.h"
24#include "KDbLookupFieldSchema.h"
25#include "KDbQuerySchema.h"
26#include "kdb_debug.h"
27
28//! @internal
29class Q_DECL_HIDDEN KDbTableSchema::Private
30{
31public:
32 Private(KDbTableSchema *t)
33 : q(t)
34 , anyNonPKField(nullptr)
35 , conn(nullptr)
36 , pkey(nullptr)
37 , query(nullptr)
38 {
39 }
40
41 ~Private() {
42 clearLookupFields();
43 qDeleteAll(indices);
44 delete query;
45 }
46
47 void clearLookupFields() {
48 qDeleteAll(lookupFields);
49 lookupFields.clear();
50 }
51
52 void addIndex(KDbIndexSchema *index) {
53 indices.append(index);
54 index->setTable(q);
55 }
56
57 KDbTableSchema * const q;
58 KDbField *anyNonPKField;
60 QVector<KDbLookupFieldSchema*> lookupFieldsList;
62 //! @todo IMPORTANT: use something like QPointer<KDbConnection> conn
63 KDbConnection *conn;
64 KDbIndexSchema *pkey;
65 KDbQuerySchema *query; //!< cached query schema that is defined by "select * from <this_table_name>"
66private:
67 Q_DISABLE_COPY(Private)
68};
69
70//-------------------------------------
71
72KDbTableSchema::KDbTableSchema(const QString& name)
73 : KDbFieldList(true)
74 , KDbObject(KDb::TableObjectType)
75 , d(new Private(this))
76{
77 setName(name);
78 init(nullptr);
79}
80
81KDbTableSchema::KDbTableSchema(const KDbObject& other)
82 : KDbFieldList(true)
83 , KDbObject(other)
84 , d(new Private(this))
85{
86 init(nullptr);
87}
88
89KDbTableSchema::KDbTableSchema()
90 : KDbFieldList(true)
91 , KDbObject(KDb::TableObjectType)
92 , d(new Private(this))
93{
94 init(nullptr);
95}
96
97KDbTableSchema::KDbTableSchema(const KDbTableSchema& ts, bool copyId)
98 : KDbFieldList(static_cast<const KDbFieldList&>(ts))
99 , KDbObject(static_cast<const KDbObject&>(ts))
100 , d(new Private(this))
101{
102 init(ts, copyId);
103}
104
105KDbTableSchema::KDbTableSchema(const KDbTableSchema& ts, int id)
106 : KDbFieldList(static_cast<const KDbFieldList&>(ts))
107 , KDbObject(static_cast<const KDbObject&>(ts))
108 , d(new Private(this))
109{
110 init(ts, false);
111 setId(id);
112}
113
114// used by KDbConnection
115KDbTableSchema::KDbTableSchema(KDbConnection *conn, const QString & name)
116 : KDbFieldList(true)
117 , KDbObject(KDb::TableObjectType)
118 , d(new Private(this))
119{
120 setName(name);
121 init(conn);
122}
123
124KDbTableSchema::~KDbTableSchema()
125{
126 if (d->conn) {
127 d->conn->removeMe(this);
128 }
129 delete d;
130}
131
132void KDbTableSchema::init(KDbConnection* conn)
133{
134 d->conn = conn;
135 d->pkey = new KDbIndexSchema;
136 d->addIndex(d->pkey);
137}
138
139void KDbTableSchema::init(const KDbTableSchema& ts, bool copyId)
140{
141 d->conn = ts.connection();
142 setName(ts.name());
143 d->pkey = nullptr; //will be copied
144 if (!copyId)
145 setId(-1);
146
147 //deep copy all members
148 foreach(KDbIndexSchema* otherIdx, *ts.indices()) {
149 // fields from _this_ table will be assigned to the index
150 KDbIndexSchema *idx = copyIndexFrom(*otherIdx);
151 if (idx->isPrimaryKey()) {//assign pkey
152 d->pkey = idx;
153 }
154 }
155
158 for (; iter != fieldsIteratorConstEnd(); ++tsIter, ++iter) {
159 const KDbLookupFieldSchema *lookup = ts.lookupFieldSchema(**tsIter);
160 if (lookup) {
161 d->lookupFields.insert(*iter, new KDbLookupFieldSchema(*lookup));
162 }
163 }
164}
165
167{
168 return d->pkey;
169}
170
172{
173 return d->pkey;
174}
175
176const QList<KDbIndexSchema*>::ConstIterator KDbTableSchema::indicesIterator() const
177{
179}
180
181const QList<KDbIndexSchema*>* KDbTableSchema::indices() const
182{
183 return &d->indices;
184}
185
187{
188 if (index && !d->indices.contains(index)) {
189 d->addIndex(index);
190 return true;
191 }
192 return false;
193}
194
196{
197 if (index) {
198 d->indices.removeOne(index);
199 return true;
200 }
201 return false;
202}
203
205{
206 KDbIndexSchema *newIndex = new KDbIndexSchema(index, this);
207 addIndex(newIndex);
208 return newIndex;
209}
210
212{
213 return dynamic_cast<const KDbInternalTableSchema*>(this);
214}
215
217{
218 if (pkey && !d->indices.contains(pkey)) {
219 kdbWarning() << *pkey << "index can't be made primary key because it does not belong "
220 "to table schema" << name();
221 return;
222 }
223 if (d->pkey && d->pkey != pkey) {
224 if (d->pkey->fieldCount() == 0) {//this is empty key, probably default - remove it
225 d->indices.removeOne(d->pkey);
226 delete d->pkey;
227 }
228 else {
229 d->pkey->setPrimaryKey(false); //there can be only one pkey..
230 //that's ok, the old pkey is still on indices list, if not empty
231 }
232 }
233
234 if (!pkey) {//clearing - set empty pkey
235 pkey = new KDbIndexSchema;
236 d->addIndex(pkey);
237 }
238 d->pkey = pkey; //!< @todo
239 d->pkey->setPrimaryKey(true);
240 d->anyNonPKField = nullptr; //for safety
241}
242
244{
245 if (!field) {
246 return false;
247 }
248 KDbField::List *fieldsList = fields();
250 if (!field || index > fieldsList->count()) {
251 return false;
252 }
253 field->setTable(this);
254 field->setOrder(index);
255 //update order for next next fields
256 const int fieldCount = fieldsList->count();
257 for (int i = index + 1; i < fieldCount; i++) {
258 fieldsList->at(i)->setOrder(i);
259 }
260
261 //Check for auto-generated indices:
262 KDbIndexSchema *idx = nullptr;
263 if (field->isPrimaryKey()) {// this is auto-generated single-field unique index
264 idx = new KDbIndexSchema;
265 d->addIndex(idx);
266 idx->setAutoGenerated(true);
267 const bool ok = idx->addField(field);
268 Q_ASSERT(ok);
269 setPrimaryKey(idx);
270 }
271 if (field->isUniqueKey()) {
272 if (!idx) {
273 idx = new KDbIndexSchema;
274 d->addIndex(idx);
275 idx->setAutoGenerated(true);
276 const bool ok = idx->addField(field);
277 Q_ASSERT(ok);
278 }
279 idx->setUnique(true);
280 }
281 if (field->isIndexed()) {// this is auto-generated single-field
282 if (!idx) {
283 idx = new KDbIndexSchema;
284 d->addIndex(idx);
285 idx->setAutoGenerated(true);
286 const bool ok = idx->addField(field);
287 Q_ASSERT(ok);
288 }
289 }
290 return true;
291}
292
294{
295 KDbLookupFieldSchema* lookup = d->lookupFields.take(field);
297 return false;
298 }
299 if (d->anyNonPKField && field == d->anyNonPKField) //d->anyNonPKField will be removed!
300 d->anyNonPKField = nullptr;
301 delete lookup;
302 return true;
303}
304
306{
307 d->indices.clear();
308 d->clearLookupFields();
311 d->conn = nullptr;
312}
313
315{
316 dbg.nospace() << static_cast<const KDbFieldList&>(*this);
317 for (const KDbField *f : *fields()) {
318 const KDbLookupFieldSchema *lookupSchema = lookupFieldSchema(*f);
319 if (lookupSchema)
320 dbg.nospace() << '\n' << f->name() << *lookupSchema;
321 }
322 return dbg.space();
323}
324
325QDebug operator<<(QDebug dbg, const KDbTableSchema& table)
326{
327 dbg.nospace() << "TABLE";
328 dbg.space() << static_cast<const KDbObject&>(table) << '\n';
329 table.debugFields(dbg);
330 return dbg.space();
331}
332
334{
335 dbg.nospace() << "INTERNAL_TABLE";
336 dbg.space() << static_cast<const KDbObject&>(table) << '\n';
337 table.debugFields(dbg);
338 return dbg.space();
339}
340
342{
343 return d->conn;
344}
345
347{
348 d->conn = conn;
349}
350
352{
353 if (d->query)
354 return d->query;
355 d->query = new KDbQuerySchema(this); //it's owned by me
356 return d->query;
357}
358
360{
361 if (!d->anyNonPKField) {
362 KDbField *f = nullptr;
363 for (QListIterator<KDbField*> it(*fields()); it.hasPrevious();) {
364 f = it.previous();
365 if (!f->isPrimaryKey() && (!d->pkey || !d->pkey->hasField(*f)))
366 break;
367 }
368 d->anyNonPKField = f;
369 }
370 return d->anyNonPKField;
371}
372
373bool KDbTableSchema::setLookupFieldSchema(const QString& fieldName, KDbLookupFieldSchema *lookupFieldSchema)
374{
375 KDbField *f = field(fieldName);
376 if (!f) {
377 kdbWarning() << "no such field" << fieldName << "in table" << name();
378 return false;
379 }
380 delete d->lookupFields.take(f);
381 if (lookupFieldSchema) {
382 d->lookupFields.insert(f, lookupFieldSchema);
383 }
384 d->lookupFieldsList.clear(); //this will force to rebuid the internal cache
385 return true;
386}
387
389{
390 return d->lookupFields.value(&field);
391}
392
394{
395 return d->lookupFields.value(&field);
396}
397
399{
400 KDbField *f = KDbTableSchema::field(fieldName);
401 if (!f)
402 return nullptr;
403 return lookupFieldSchema(*f);
404}
405
407{
408 if (d->lookupFields.isEmpty())
410 if (!d->lookupFields.isEmpty() && !d->lookupFieldsList.isEmpty())
411 return d->lookupFieldsList; //already updated
412 //update
413 d->lookupFieldsList.clear();
414 d->lookupFieldsList.resize(d->lookupFields.count());
415 int i = 0;
416 for (KDbField* f : *fields()) {
418 if (itMap != d->lookupFields.constEnd()) {
419 d->lookupFieldsList[i] = itMap.value();
420 i++;
421 }
422 }
423 return d->lookupFieldsList;
424}
425
426//--------------------------------------
427
428class Q_DECL_HIDDEN KDbInternalTableSchema::Private
429{
430public:
431 Private() {}
432 bool dummy = false;
433};
434
435KDbInternalTableSchema::KDbInternalTableSchema(const QString& name)
437 , d(new Private)
438{
439}
440
441KDbInternalTableSchema::KDbInternalTableSchema(const KDbTableSchema& ts)
442 : KDbTableSchema(ts, false)
443 , d(new Private)
444{
445}
446
447KDbInternalTableSchema::KDbInternalTableSchema(const KDbInternalTableSchema& ts)
448 : KDbTableSchema(ts, false)
449 , d(new Private)
450{
451}
452
453KDbInternalTableSchema::~KDbInternalTableSchema()
454{
455 delete d;
456}
Provides database connection, allowing queries and data modification.
void removeMe(KDbTableSchema *ts)
bool hasField(const KDbField &field) const
virtual bool removeField(KDbField *field)
virtual KDbField * field(int id)
virtual void clear()
KDbField::ListIterator fieldsIterator() const
int fieldCount() const
KDbField::ListIterator fieldsIteratorConstEnd() const
virtual bool insertField(int index, KDbField *field)
KDbField::List * fields()
Meta-data for a field.
Definition KDbField.h:72
QList< KDbField * >::ConstIterator ListIterator
iterator for list of fields
Definition KDbField.h:79
bool isIndexed() const
Definition KDbField.h:312
bool isUniqueKey() const
Definition KDbField.h:292
void setOrder(int order)
Definition KDbField.cpp:311
bool isPrimaryKey() const
Definition KDbField.h:287
void setTable(KDbTableSchema *table)
Definition KDbField.cpp:595
Provides information about database index that can be created for a database table.
virtual bool addField(KDbField *field)
void setAutoGenerated(bool set)
void setPrimaryKey(bool set)
bool isPrimaryKey() const
void setUnique(bool set)
void setTable(KDbTableSchema *table)
Assigns this index to table table() must be nullptr and table must be not be nullptr.
Provides information about lookup field's setup.
virtual void clear()
Clears all properties except 'type'.
Definition KDbObject.cpp:34
KDbQuerySchema provides information about database query.
QVector< KDbLookupFieldSchema * > lookupFields() const
void setConnection(KDbConnection *conn)
KDbLookupFieldSchema * lookupFieldSchema(const KDbField &field)
KDbIndexSchema * copyIndexFrom(const KDbIndexSchema &index)
bool isInternal() const
KDbField * anyNonPKField()
bool removeField(KDbField *field) override
KDbConnection * connection() const
void clear() override
KDbIndexSchema * primaryKey()
bool removeIndex(KDbIndexSchema *index)
Removes index index from this table schema Ownership of the index is transferred to the table schema.
QDebug debugFields(QDebug dbg) const
bool setLookupFieldSchema(const QString &fieldName, KDbLookupFieldSchema *lookupFieldSchema)
KDbQuerySchema * query()
void setPrimaryKey(KDbIndexSchema *pkey)
bool insertField(int index, KDbField *field) override
bool addIndex(KDbIndexSchema *index)
Adds index index to this table schema Ownership of the index is transferred to the table schema.
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
KCALENDARCORE_EXPORT QDataStream & operator<<(QDataStream &out, const KCalendarCore::Alarm::Ptr &)
A database connectivity and creation framework.
void init(KXmlGuiWindow *window, KGameDifficulty *difficulty=nullptr)
QString name(GameStandardAction id)
QDebug & nospace()
QDebug & space()
const_iterator constEnd() const const
const_iterator constFind(const Key &key) const const
qsizetype count() const const
iterator insert(const Key &key, const T &value)
bool isEmpty() const const
T take(const Key &key)
T value(const Key &key) const const
const_reference at(qsizetype i) const const
void clear()
const_iterator constBegin() const const
bool contains(const AT &value) const const
qsizetype count() const const
bool removeOne(const AT &t)
bool hasPrevious() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:38:30 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.