KDb

KDbTableSchema.cpp
1 /* This file is part of the KDE project
2  Copyright (C) 2003 Joseph Wenninger <[email protected]>
3  Copyright (C) 2003-2016 JarosÅ‚aw Staniek <[email protected]>
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
29 class Q_DECL_HIDDEN KDbTableSchema::Private
30 {
31 public:
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;
61  QList<KDbIndexSchema*> indices;
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>"
66 private:
67  Q_DISABLE_COPY(Private)
68 };
69 
70 //-------------------------------------
71 
72 KDbTableSchema::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 
81 KDbTableSchema::KDbTableSchema(const KDbObject& other)
82  : KDbFieldList(true)
83  , KDbObject(other)
84  , d(new Private(this))
85 {
86  init(nullptr);
87 }
88 
89 KDbTableSchema::KDbTableSchema()
90  : KDbFieldList(true)
91  , KDbObject(KDb::TableObjectType)
92  , d(new Private(this))
93 {
94  init(nullptr);
95 }
96 
97 KDbTableSchema::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 
105 KDbTableSchema::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
115 KDbTableSchema::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 
124 KDbTableSchema::~KDbTableSchema()
125 {
126  if (d->conn) {
127  d->conn->removeMe(this);
128  }
129  delete d;
130 }
131 
132 void KDbTableSchema::init(KDbConnection* conn)
133 {
134  d->conn = conn;
135  d->pkey = new KDbIndexSchema;
136  d->addIndex(d->pkey);
137 }
138 
139 void 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 
176 const QList<KDbIndexSchema*>::ConstIterator KDbTableSchema::indicesIterator() const
177 {
178  return QList<KDbIndexSchema*>::ConstIterator (d->indices.constBegin());
179 }
180 
181 const 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 
243 bool KDbTableSchema::insertField(int index, KDbField *field)
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 
325 QDebug 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 
373 bool 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()) {
417  QHash<const KDbField*, KDbLookupFieldSchema*>::ConstIterator itMap = d->lookupFields.constFind(f);
418  if (itMap != d->lookupFields.constEnd()) {
419  d->lookupFieldsList[i] = itMap.value();
420  i++;
421  }
422  }
423  return d->lookupFieldsList;
424 }
425 
426 //--------------------------------------
427 
428 class Q_DECL_HIDDEN KDbInternalTableSchema::Private
429 {
430 public:
431  Private() {}
432  bool dummy = false;
433 };
434 
435 KDbInternalTableSchema::KDbInternalTableSchema(const QString& name)
437  , d(new Private)
438 {
439 }
440 
441 KDbInternalTableSchema::KDbInternalTableSchema(const KDbTableSchema& ts)
442  : KDbTableSchema(ts, false)
443  , d(new Private)
444 {
445 }
446 
447 KDbInternalTableSchema::KDbInternalTableSchema(const KDbInternalTableSchema& ts)
448  : KDbTableSchema(ts, false)
449  , d(new Private)
450 {
451 }
452 
453 KDbInternalTableSchema::~KDbInternalTableSchema()
454 {
455  delete d;
456 }
bool removeIndex(KDbIndexSchema *index)
Removes index index from this table schema Ownership of the index is transferred to the table schema.
const T value(const Key &key) const const
std::optional< QSqlQuery > query(const QString &queryStatement)
bool isPrimaryKey() const
Definition: KDbField.h:287
KCALENDARCORE_EXPORT QDataStream & operator<<(QDataStream &out, const KCalendarCore::Alarm::Ptr &)
Provides information about lookup field's setup.
KDbIndexSchema * primaryKey()
bool isIndexed() const
Definition: KDbField.h:312
KDbQuerySchema * query()
bool hasPrevious() const const
KDbField::ListIterator fieldsIterator() const
int count(const T &value) const const
virtual KDbField * field(int id)
QDebug & nospace()
A database connectivity and creation framework.
KDbConnection * connection() const
QString name
KDbIndexSchema * copyIndexFrom(const KDbIndexSchema &index)
void setOrder(int order)
Definition: KDbField.cpp:311
QDebug & space()
bool isUniqueKey() const
Definition: KDbField.h:292
virtual bool insertField(int index, KDbField *field)
void setTable(KDbTableSchema *table)
Definition: KDbField.cpp:595
void clear() override
void setConnection(KDbConnection *conn)
virtual void clear()
Clears all properties except 'type'.
Definition: KDbObject.cpp:34
void setAutoGenerated(bool set)
bool isInternal() const
bool removeField(KDbField *field) override
bool insertField(int index, KDbField *field) override
const T & at(int i) const const
void init(KXmlGuiWindow *window, KgDifficulty *difficulty=nullptr)
bool addIndex(KDbIndexSchema *index)
Adds index index to this table schema Ownership of the index is transferred to the table schema.
bool isPrimaryKey() const
virtual bool removeField(KDbField *field)
QList< KDbField * >::ConstIterator ListIterator
iterator for list of fields
Definition: KDbField.h:79
KDbField::List * fields()
typedef ConstIterator
Provides information about database index that can be created for a database table.
bool setLookupFieldSchema(const QString &fieldName, KDbLookupFieldSchema *lookupFieldSchema)
KDbQuerySchema provides information about database query.
void setPrimaryKey(KDbIndexSchema *pkey)
const char * name(StandardAction id)
Meta-data for a field.
Definition: KDbField.h:71
int fieldCount() 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 database connection, allowing queries and data modification.
Definition: KDbConnection.h:51
QDebug debugFields(QDebug dbg) const
KDbField::ListIterator fieldsIteratorConstEnd() const
virtual bool addField(KDbField *field)
virtual void clear()
KDbField * anyNonPKField()
QVector< KDbLookupFieldSchema * > lookupFields() const
KDbLookupFieldSchema * lookupFieldSchema(const KDbField &field)
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Fri Jun 9 2023 04:07:16 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.