File indexing completed on 2024-04-14 14:53:31

0001 /* This file is part of the KDE project
0002    Copyright (C) 2003-2016 Jarosław Staniek <staniek@kde.org>
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This library is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this library; see the file COPYING.LIB.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #include "KDbConnection.h"
0021 #include "KDbDriver.h"
0022 #include "KDbIndexSchema.h"
0023 #include "KDbRelationship.h"
0024 #include "KDbTableSchema.h"
0025 #include "kdb_debug.h"
0026 
0027 class Q_DECL_HIDDEN KDbIndexSchema::Private
0028 {
0029 public:
0030     Private()
0031         : tableSchema(nullptr)
0032         , isPrimary(false)
0033         , isUnique(false)
0034         , isAutoGenerated(false)
0035         , isForeignKey(false)
0036     {
0037     }
0038     ~Private()
0039     {
0040         /* It's a list of relationships to the table (of this index), i.e. any such
0041          * relationship in which the table is at 'master' side will be cleared and
0042          * relationships will be destroyed.
0043          * So all these relationships must be detached from details-side, corresponding
0044          * indices.
0045          */
0046         for (KDbRelationship* rel : qAsConst(masterOwnedRelationships)) {
0047             if (rel->detailsIndex()) {
0048                 rel->detailsIndex()->detachRelationship(rel);
0049             }
0050         }
0051         qDeleteAll(masterOwnedRelationships);
0052     }
0053 
0054     //! table on that index is built
0055     KDbTableSchema *tableSchema;
0056 
0057     /*! A set of master relationships for the table (of this index),
0058      this index is a master key for these relationships
0059      and therefore - owner of these */
0060     QSet<KDbRelationship*> masterOwnedRelationships;
0061 
0062     /*! A list of master relationships that are not owned by this schema */
0063     QList<const KDbRelationship*> masterRelationships;
0064 
0065     /*! A list of relationships to table (of this index) */
0066     QList<const KDbRelationship*> detailsRelationships;
0067 
0068     bool isPrimary;
0069     bool isUnique;
0070     bool isAutoGenerated;
0071     bool isForeignKey;
0072 };
0073 
0074 KDbIndexSchema::KDbIndexSchema()
0075         : KDbFieldList(false)//fields are not owned by KDbIndexSchema object
0076         , KDbObject(KDb::IndexObjectType)
0077         , d(new Private)
0078 {
0079 }
0080 
0081 KDbIndexSchema::KDbIndexSchema(const KDbIndexSchema& index, KDbTableSchema* parentTable)
0082         : KDbFieldList(false)//fields are not owned by KDbIndexSchema object
0083         , KDbObject(static_cast<const KDbObject&>(index))
0084         , d(new Private)
0085 {
0086     d->isPrimary = index.isPrimaryKey();
0087     d->isUnique = index.isUnique();
0088     d->isAutoGenerated = index.isAutoGenerated();
0089     d->isForeignKey = index.isForeignKey();
0090     // deep copy the field references
0091     for(KDbField *f : *index.fields()) {
0092         KDbField *parentTableField = parentTable->field(f->name());
0093         if (!parentTableField) {
0094             kdbWarning() << "Could not find field" << f->name() << "in parentTable. Empty index will be created!";
0095             KDbFieldList::clear();
0096             break;
0097         }
0098         (void)KDbFieldList::addField(f);
0099     }
0100 
0101 //! @todo copy relationships!
0102 // Reference::List m_refs_to; //! list of references to table (of this index)
0103 // Reference::List m_refs_from; //! list of references from the table (of this index),
0104 //         //! this index is foreign key for these references
0105 //         //! and therefore - owner of these
0106 }
0107 
0108 KDbIndexSchema::~KDbIndexSchema()
0109 {
0110     delete d;
0111 }
0112 
0113 void KDbIndexSchema::setTable(KDbTableSchema *table)
0114 {
0115     if (this->table()) {
0116         kdbWarning() << "Table is already assigned to this index";
0117         return;
0118     }
0119     if (table) {
0120         d->tableSchema = table;
0121     }
0122 }
0123 
0124 bool KDbIndexSchema::addField(KDbField *field)
0125 {
0126     if (!d->tableSchema || field->table() != d->tableSchema) {
0127         kdbWarning() << (field ? field->name() : QString())
0128         << "WARNING: field does not belong to the same table"
0129         << (field && field->table() ? field->table()->name() : QString())
0130         << "as index!";
0131         return false;
0132     }
0133     return KDbFieldList::addField(field);
0134 }
0135 
0136 const KDbTableSchema* KDbIndexSchema::table() const
0137 {
0138     return d->tableSchema;
0139 }
0140 
0141 KDbTableSchema* KDbIndexSchema::table()
0142 {
0143     return d->tableSchema;
0144 }
0145 
0146 QList<const KDbRelationship*> KDbIndexSchema::masterRelationships() const
0147 {
0148     return d->masterRelationships;
0149 }
0150 
0151 QList<const KDbRelationship*> KDbIndexSchema::detailsRelationships() const
0152 {
0153     return d->detailsRelationships;
0154 }
0155 
0156 bool KDbIndexSchema::isAutoGenerated() const
0157 {
0158     return d->isAutoGenerated;
0159 }
0160 
0161 void KDbIndexSchema::setAutoGenerated(bool set)
0162 {
0163     d->isAutoGenerated = set;
0164 }
0165 
0166 bool KDbIndexSchema::isPrimaryKey() const
0167 {
0168     return d->isPrimary;
0169 }
0170 
0171 void KDbIndexSchema::setPrimaryKey(bool set)
0172 {
0173     d->isPrimary = set;
0174     if (d->isPrimary)
0175         d->isUnique = true;
0176 }
0177 
0178 bool KDbIndexSchema::isUnique() const
0179 {
0180     return d->isUnique;
0181 }
0182 
0183 void KDbIndexSchema::setUnique(bool set)
0184 {
0185     d->isUnique = set;
0186     if (!d->isUnique)
0187         d->isPrimary = false;
0188 }
0189 
0190 bool KDbIndexSchema::isForeignKey() const
0191 {
0192     return d->isForeignKey;
0193 }
0194 
0195 void KDbIndexSchema::setForeignKey(bool set)
0196 {
0197     d->isForeignKey = set;
0198     if (d->isForeignKey) {
0199         setUnique(false);
0200     }
0201     if (fieldCount() == 1) {
0202         fields()->first()->setForeignKey(true);
0203     }
0204 }
0205 
0206 KDB_EXPORT QDebug operator<<(QDebug dbg, const KDbIndexSchema& index)
0207 {
0208     dbg.nospace() << QLatin1String("INDEX");
0209     dbg.space() << static_cast<const KDbObject&>(index) << '\n';
0210     dbg.space() << (index.isForeignKey() ? "FOREIGN KEY" : "");
0211     dbg.space() << (index.isAutoGenerated() ? "AUTOGENERATED" : "");
0212     dbg.space() << (index.isPrimaryKey() ? "PRIMARY" : "");
0213     dbg.space() << ((!index.isPrimaryKey()) && index.isUnique() ? "UNIQUE" : "");
0214     dbg.space() << static_cast<const KDbFieldList&>(index);
0215     return dbg.space();
0216 }
0217 
0218 void KDbIndexSchema::attachRelationship(KDbRelationship *rel)
0219 {
0220     attachRelationship(rel, true);
0221 }
0222 
0223 void KDbIndexSchema::attachRelationship(KDbRelationship *rel, bool ownedByMaster)
0224 {
0225     if (!rel)
0226         return;
0227     if (rel->masterIndex() == this) {
0228         if (ownedByMaster) {
0229             if (!d->masterOwnedRelationships.contains(rel)) {
0230                 d->masterOwnedRelationships.insert(rel);
0231             }
0232         } else {//not owned
0233             if (!d->masterRelationships.contains(rel)) {
0234                 d->masterRelationships.append(rel);
0235             }
0236         }
0237     } else if (rel->detailsIndex() == this) {
0238         if (!d->detailsRelationships.contains(rel)) {
0239             d->detailsRelationships.append(rel);
0240         }
0241     }
0242 }
0243 
0244 void KDbIndexSchema::detachRelationship(KDbRelationship *rel)
0245 {
0246     if (!rel)
0247         return;
0248     d->masterOwnedRelationships.remove(rel);   //for sanity
0249     d->masterRelationships.takeAt(d->masterRelationships.indexOf(rel));   //for sanity
0250     d->detailsRelationships.takeAt(d->detailsRelationships.indexOf(rel));   //for sanity
0251 }