Skip to content

Commit bf505ed

Browse files
committed
Code refactoring
This commit refactors vast parts of the sqlitetypes.h interface. Its main goals are: less code, easier code, a more modern interface, reduced likelihood for strange errors and more flexibility for future extensions. The main reason why the sqlitetypes.h functions were working so well in DB4S was not because they were that stable but because they were extremely interlinked with the rest of the code. This is fine because we do not plan to ship them as a separate library. But it makes it hard to find the obvious spot to fix an issue or to put a new function. It can always be done in the sqlitetypes function or in the rest of the DB4S code because it is just not clear what the interface between the two should look like. This is supposed to be improved by this commit. One main thing here is to make ownership of objects a bit clearer. In theory the new code should be faster too but that difference will be neglectable from a user POV. This commit also fixes a hidden bug which caused all table constraints to be removed in the Edit Table dialog when a single field was removed from the table. This is all still WIP and more work is needed to be done here.
1 parent f3e6aec commit bf505ed

16 files changed

+688
-795
lines changed

src/AddRecordDialog.cpp

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ AddRecordDialog::AddRecordDialog(DBBrowserDB& db, const sqlb::ObjectIdentifier&
112112
ui(new Ui::AddRecordDialog),
113113
pdb(db),
114114
curTable(tableName),
115-
m_table(*(pdb.getObjectByName(curTable).dynamicCast<sqlb::Table>()))
115+
m_table(*(pdb.getObjectByName<sqlb::Table>(curTable)))
116116
{
117117
// Create UI
118118
ui->setupUi(this);
@@ -174,43 +174,42 @@ void AddRecordDialog::populateFields()
174174
ui->treeWidget->setItemDelegateForColumn(kType, new NoEditDelegate(this));
175175
ui->treeWidget->setItemDelegateForColumn(kValue, new EditDelegate(this));
176176

177-
const sqlb::FieldVector& fields = m_table.fields();
178-
const sqlb::FieldVector& pk = m_table.primaryKey();
179-
for(const sqlb::FieldPtr& f : fields)
177+
const auto& fields = m_table.fields;
178+
const QStringList& pk = m_table.primaryKey();
179+
for(const sqlb::Field& f : fields)
180180
{
181181
QTreeWidgetItem *tbitem = new QTreeWidgetItem(ui->treeWidget);
182182

183183
tbitem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable);
184184

185-
tbitem->setText(kName, f->name());
186-
tbitem->setText(kType, f->type());
187-
tbitem->setData(kType, Qt::UserRole, f->affinity());
185+
tbitem->setText(kName, f.name());
186+
tbitem->setText(kType, f.type());
187+
tbitem->setData(kType, Qt::UserRole, f.affinity());
188188

189189
// NOT NULL fields are indicated in bold.
190-
if (f->notnull()) {
190+
if (f.notnull()) {
191191
QFont font;
192192
font.setBold(true);
193193
tbitem->setData(kName, Qt::FontRole, font);
194194
}
195-
if (pk.contains(f))
195+
if (contains(pk, f.name()))
196196
tbitem->setIcon(kName, QIcon(":/icons/field_key"));
197197
else
198198
tbitem->setIcon(kName, QIcon(":/icons/field"));
199199

200-
QString defaultValue = f->defaultValue();
200+
QString defaultValue = f.defaultValue();
201201
QString toolTip;
202202

203-
if (f->autoIncrement())
203+
if (f.autoIncrement())
204204
toolTip.append(tr("Auto-increment\n"));
205205

206-
if (f->unique())
206+
if (f.unique())
207207
toolTip.append(tr("Unique constraint\n"));
208208

209-
if (!f->check().isEmpty())
210-
toolTip.append(tr("Check constraint:\t %1\n").arg (f->check()));
209+
if (!f.check().isEmpty())
210+
toolTip.append(tr("Check constraint:\t %1\n").arg (f.check()));
211211

212-
QSharedPointer<sqlb::ForeignKeyClause> fk =
213-
m_table.constraint({f}, sqlb::Constraint::ForeignKeyConstraintType).dynamicCast<sqlb::ForeignKeyClause>();
212+
auto fk = std::dynamic_pointer_cast<sqlb::ForeignKeyClause>(m_table.constraint({f.name()}, sqlb::Constraint::ForeignKeyConstraintType));
214213
if(fk)
215214
toolTip.append(tr("Foreign key:\t %1\n").arg(fk->toString()));
216215

@@ -219,7 +218,7 @@ void AddRecordDialog::populateFields()
219218
// Display Role is used for displaying the default values.
220219
// Only when they are changed, the User Role is updated and then used in the INSERT query.
221220
if (!defaultValue.isEmpty()) {
222-
tbitem->setData(kValue, Qt::DisplayRole, f->defaultValue());
221+
tbitem->setData(kValue, Qt::DisplayRole, f.defaultValue());
223222
toolTip.append(tr("Default value:\t %1\n").arg (defaultValue));
224223
} else
225224
tbitem->setData(kValue, Qt::DisplayRole, Settings::getValue("databrowser", "null_text"));

src/DbStructureModel.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -326,12 +326,7 @@ void DbStructureModel::buildTree(QTreeWidgetItem* parent, const QString& schema)
326326
{
327327
QStringList pk_columns;
328328
if(it->type() == sqlb::Object::Types::Table)
329-
{
330-
sqlb::FieldVector pk = it.dynamicCast<sqlb::Table>()->primaryKey();
331-
for(const sqlb::FieldPtr& pk_col : pk)
332-
pk_columns.push_back(pk_col->name());
333-
334-
}
329+
pk_columns = std::dynamic_pointer_cast<sqlb::Table>(it)->primaryKey();
335330
for(const sqlb::FieldInfo& field : fieldList)
336331
{
337332
QTreeWidgetItem *fldItem = new QTreeWidgetItem(item);

src/DbStructureModel.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
#define DBSTRUCTUREMODEL_H
33

44
#include <QAbstractItemModel>
5+
#include <memory>
56

67
class DBBrowserDB;
78
class QTreeWidgetItem;
8-
namespace sqlb { class Object; typedef QSharedPointer<Object> ObjectPtr; }
9+
namespace sqlb { class Object; using ObjectPtr = std::shared_ptr<Object>; }
910

1011
class DbStructureModel : public QAbstractItemModel
1112
{

src/EditIndexDialog.cpp

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ EditIndexDialog::EditIndexDialog(DBBrowserDB& db, const sqlb::ObjectIdentifier&
5353
if(!newIndex)
5454
{
5555
// Load the current layout and fill in the dialog fields
56-
index = *(pdb.getObjectByName(curIndex).dynamicCast<sqlb::Index>());
56+
index = *(pdb.getObjectByName<sqlb::Index>(curIndex));
5757

5858
ui->editIndexName->blockSignals(true);
5959
ui->editIndexName->setText(index.name());
@@ -77,7 +77,7 @@ EditIndexDialog::EditIndexDialog(DBBrowserDB& db, const sqlb::ObjectIdentifier&
7777
connect(ui->tableIndexColumns, static_cast<void(QTableWidget::*)(QTableWidgetItem*)>(&QTableWidget::itemChanged),
7878
[=](QTableWidgetItem* item)
7979
{
80-
index.columns().at(item->row())->setName(item->text());
80+
index.fields[item->row()].setName(item->text());
8181
updateSqlText();
8282
});
8383

@@ -96,7 +96,7 @@ void EditIndexDialog::tableChanged(const QString& new_table, bool initialLoad)
9696
if(!initialLoad)
9797
{
9898
index.setTable(sqlb::ObjectIdentifier(ui->comboTableName->currentData()).name());
99-
index.clearColumns();
99+
index.fields.clear();
100100
}
101101

102102
// Stop here if table name is empty
@@ -113,18 +113,18 @@ void EditIndexDialog::tableChanged(const QString& new_table, bool initialLoad)
113113
void EditIndexDialog::updateColumnLists()
114114
{
115115
// Fill the table column list
116-
sqlb::TablePtr table = pdb.getObjectByName(sqlb::ObjectIdentifier(ui->comboTableName->currentData())).dynamicCast<sqlb::Table>();
116+
sqlb::TablePtr table = pdb.getObjectByName<sqlb::Table>(sqlb::ObjectIdentifier(ui->comboTableName->currentData()));
117117
if(!table)
118118
return;
119119
sqlb::FieldInfoList tableFields = table->fieldInformation();
120120
ui->tableTableColumns->setRowCount(tableFields.size());
121121
int tableRows = 0;
122-
for(int i=0;i<tableFields.size();++i)
122+
for(size_t i=0;i<tableFields.size();++i)
123123
{
124124
// When we're doing the initial loading and this field already is in the index to edit, then don't add it to the
125125
// list of table columns. It will be added to the list of index columns in the next step. When this is not the initial
126126
// loading, the index column list is empty, so this check will always be true.
127-
if(index.findColumn(tableFields.at(i).name) == -1)
127+
if(sqlb::findField(index, tableFields.at(i).name) == index.fields.end())
128128
{
129129
// Put the name of the field in the first column
130130
QTableWidgetItem* name = new QTableWidgetItem(tableFields.at(i).name);
@@ -145,15 +145,15 @@ void EditIndexDialog::updateColumnLists()
145145

146146
// Fill the index column list. This is done separately from the table column to include expression columns (these are not found in the original
147147
// table) and to preserve the order of the index columns
148-
auto indexFields = index.columns();
148+
auto indexFields = index.fields;
149149
ui->tableIndexColumns->blockSignals(true);
150150
ui->tableIndexColumns->setRowCount(indexFields.size());
151-
for(int i=0;i<indexFields.size();++i)
151+
for(size_t i=0;i<indexFields.size();++i)
152152
{
153153
// Put the name of the field in the first column
154-
QTableWidgetItem* name = new QTableWidgetItem(indexFields.at(i)->name());
154+
QTableWidgetItem* name = new QTableWidgetItem(indexFields.at(i).name());
155155
Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
156-
if(indexFields.at(i)->expression())
156+
if(indexFields.at(i).expression())
157157
flags |= Qt::ItemIsEditable;
158158
name->setFlags(flags);
159159
ui->tableIndexColumns->setItem(i, 0, name);
@@ -163,15 +163,15 @@ void EditIndexDialog::updateColumnLists()
163163
order->addItem("");
164164
order->addItem("ASC");
165165
order->addItem("DESC");
166-
order->setCurrentText(indexFields.at(i)->order().toUpper());
166+
order->setCurrentText(indexFields.at(i).order().toUpper());
167167
ui->tableIndexColumns->setCellWidget(i, 1, order);
168168
connect(order, static_cast<void(QComboBox::*)(const QString&)>(&QComboBox::currentTextChanged),
169169
[=](QString new_order)
170170
{
171-
int colnum = index.findColumn(indexFields.at(i)->name());
172-
if(colnum != -1)
171+
auto colnum = sqlb::findField(index, indexFields.at(i).name());
172+
if(colnum != index.fields.end())
173173
{
174-
index.column(colnum)->setOrder(new_order);
174+
colnum->setOrder(new_order);
175175
updateSqlText();
176176
}
177177
});
@@ -195,10 +195,10 @@ void EditIndexDialog::addToIndex(const QModelIndex& idx)
195195
return;
196196

197197
// Add field to index
198-
index.addColumn(sqlb::IndexedColumnPtr(new sqlb::IndexedColumn(
199-
ui->tableTableColumns->item(row, 0)->text(), // Column name
200-
false, // Is expression
201-
""))); // Order
198+
index.fields.emplace_back(
199+
ui->tableTableColumns->item(row, 0)->text(), // Column name
200+
false, // Is expression
201+
""); // Order
202202

203203
// Update UI
204204
updateColumnLists();
@@ -220,14 +220,14 @@ void EditIndexDialog::removeFromIndex(const QModelIndex& idx)
220220
// If this is an expression column and the action was triggered by a double click event instead of a button click,
221221
// we won't remove the expression column because it's too likely that this was only done by accident by the user.
222222
// Instead just open the expression column for editing.
223-
if(index.column(row)->expression() && sender() != ui->buttonFromIndex)
223+
if(index.fields[row].expression() && sender() != ui->buttonFromIndex)
224224
{
225225
ui->tableIndexColumns->editItem(ui->tableIndexColumns->item(row, 0));
226226
return;
227227
}
228228

229229
// Remove column from index
230-
index.removeColumn(ui->tableIndexColumns->item(row, 0)->text());
230+
sqlb::removeField(index, ui->tableIndexColumns->item(row, 0)->text());
231231

232232
// Update UI
233233
updateColumnLists();
@@ -245,7 +245,7 @@ void EditIndexDialog::checkInput()
245245
valid = false;
246246

247247
// Check if index has any columns
248-
if(index.columns().size() == 0)
248+
if(index.fields.size() == 0)
249249
valid = false;
250250

251251
// Only activate OK button if index data is valid
@@ -312,10 +312,8 @@ void EditIndexDialog::moveCurrentColumn(bool down)
312312
if(newRow >= ui->tableIndexColumns->rowCount())
313313
return;
314314

315-
// Get the column information, swap the columns, and save the new column list back in the index
316-
auto columns = index.columns();
317-
std::swap(columns[currentRow], columns[newRow]);
318-
index.setColumns(columns);
315+
// Swap the columns
316+
std::swap(index.fields[currentRow], index.fields[newRow]);
319317

320318
// Update UI
321319
updateColumnLists();
@@ -327,16 +325,17 @@ void EditIndexDialog::moveCurrentColumn(bool down)
327325
void EditIndexDialog::addExpressionColumn()
328326
{
329327
// Check if there already is an empty expression column
330-
int row = index.findColumn("");
331-
if(row == -1)
328+
auto field_it = sqlb::findField(index, "");
329+
int row = std::distance(index.fields.begin(), field_it);
330+
if(field_it == index.fields.end())
332331
{
333332
// There is no empty expression column yet, so add one.
334333

335334
// Add new expression column to the index
336-
index.addColumn(sqlb::IndexedColumnPtr(new sqlb::IndexedColumn(
337-
"", // Column name
338-
true, // Is expression
339-
""))); // Order
335+
index.fields.emplace_back(
336+
"", // Column name
337+
true, // Is expression
338+
""); // Order
340339

341340
// Update UI
342341
updateColumnLists();

0 commit comments

Comments
 (0)