diff --git a/src/sqlitetypes.cpp b/src/sqlitetypes.cpp new file mode 100644 index 00000000..5a0cc15a --- /dev/null +++ b/src/sqlitetypes.cpp @@ -0,0 +1,127 @@ +#include "sqlitetypes.h" + +namespace sqlb { + +QString Field::toString(const QString& indent, const QString& sep) const +{ + QString str = indent + m_name + sep + m_type; + if(m_notnull) + str += " NOT NULL"; + if(!m_check.isEmpty()) + str += " CHECK(" + m_check + ")"; + if(m_autoincrement) + str += " PRIMARY KEY AUTOINCREMENT"; + return str; +} + +bool Field::isText() const +{ + QString norm = m_type.trimmed().toLower(); + + return norm.startsWith("character") + || norm.startsWith("varchar") + || norm.startsWith("varying character") + || norm.startsWith("nchar") + || norm.startsWith("native charactar") + || norm.startsWith("nvarchar") + || norm == "text" + || norm == "clob"; +} + +bool Field::isInteger() const +{ + QString norm = m_type.trimmed().toLower(); + + return norm == "int" + || norm == "integer" + || norm == "tinyint" + || norm == "smallint" + || norm == "mediumint" + || norm == "bigint" + || norm == "unsigned big int" + || norm == "int2" + || norm == "int8"; +} + +Table::~Table() +{ + foreach(Field* f, m_fields) { + delete f; + } + m_fields.clear(); +} + +void Table::addField(Field *f) +{ + m_fields.append(f); +} + +bool Table::setPrimaryKey(const FieldList& pk) +{ + foreach(Field* f, pk) { + if(!m_fields.contains(f)) + return false; + } + + m_primarykey = pk; + return true; +} + +bool Table::setPrimaryKey(Field* pk, bool autoincrement) +{ + if(m_fields.contains(pk)) + { + if(pk->isInteger() && autoincrement) + pk->setAutoIncrement(true); + m_primarykey.clear(); + m_primarykey.append(pk); + return true; + } + + return false; +} + +QStringList Table::fieldList() const +{ + QStringList sl; + + foreach(Field* f, m_fields) { + sl << f->toString(); + } + + return sl; +} + +bool Table::hasAutoIncrement() const +{ + foreach(Field* f, m_fields) { + if(f->autoIncrement()) + return true; + } + return false; +} + +QString Table::sql() const +{ + QString sql = QString("CREATE TABLE `%1` (\n").arg(m_name); + + sql += fieldList().join(",\n"); + + // primary key + if( m_primarykey.size() > 0 && !hasAutoIncrement()) + { + sql += ",\n\tPRIMARY KEY("; + for(QList::ConstIterator it = m_primarykey.constBegin(); + it != m_primarykey.constEnd(); + ++it) + { + sql += (*it)->name(); + if(it != --m_primarykey.constEnd()) + sql += ","; + } + sql += ")"; + } + + return sql + "\n)"; +} +} //namespace sqlb diff --git a/src/sqlitetypes.h b/src/sqlitetypes.h new file mode 100644 index 00000000..21a3e466 --- /dev/null +++ b/src/sqlitetypes.h @@ -0,0 +1,63 @@ +#pragma once +#ifndef SQLITETYPES_H +#define SQLITETYPES_H + +#include +#include +#include + +namespace sqlb { + +class Field +{ +public: + Field(const QString& name, const QString& type, bool notnull = false, const QString& check = "") + : m_name(name), m_type(type), m_notnull(notnull), m_check(check), m_autoincrement(false) {} + + QString toString(const QString& indent = "\t", const QString& sep = "\t") const; + + void setAutoIncrement(bool autoinc) { m_autoincrement = autoinc; } + + bool isText() const; + bool isInteger() const; + + const QString& name() const { return m_name; } + const QString& type() const { return m_type; } + bool notnull() const { return m_notnull; } + const QString& check() const { return m_check; } + bool autoIncrement() const { return m_autoincrement; } +private: + QString m_name; + QString m_type; + bool m_notnull; + QString m_check; + bool m_autoincrement; //! this is stored here for simplification +}; + +typedef QList FieldList; +class Table +{ +public: + Table(const QString& name): m_name(name) {} + virtual ~Table(); + + const QString& name() const { return m_name; } + QString sql() const; + + void addField(Field* f); + + bool setPrimaryKey(const FieldList& pk); + bool setPrimaryKey(Field* pk, bool autoincrement = false); + +private: + QStringList fieldList() const; + bool hasAutoIncrement() const; + +private: + QString m_name; + FieldList m_fields; + FieldList m_primarykey; +}; +} //namespace sqlb + +#endif // SQLITETYPES_H diff --git a/src/src.pro b/src/src.pro index 186ca471..a3bdffe9 100644 --- a/src/src.pro +++ b/src/src.pro @@ -7,8 +7,7 @@ TARGET = sqlitebrowser #INCLUDEPATH += sqlite_source/ CONFIG += qt \ - warn_on \ - debug + warn_on HEADERS += \ sqlitedb.h \ @@ -24,12 +23,12 @@ HEADERS += \ EditDialog.h \ ExportCsvDialog.h \ ImportCsvDialog.h \ - sqltextedit.h + sqltextedit.h \ + sqlitetypes.h SOURCES += \ sqlitedb.cpp \ sqlbrowser_util.c \ - main.cpp \ MainWindow.cpp \ SQLiteSyntaxHighlighter.cpp \ CreateIndexDialog.cpp \ @@ -41,7 +40,16 @@ SOURCES += \ EditDialog.cpp \ ExportCsvDialog.cpp \ ImportCsvDialog.cpp \ - sqltextedit.cpp + sqltextedit.cpp \ + sqlitetypes.cpp + +# create a unittest option +CONFIG(unittest) { + CONFIG += qtestlib + SOURCES += tests/testsqlobjects.cpp +} else { + SOURCES += main.cpp +} QMAKE_CXXFLAGS += -DAPP_VERSION=\\\"`cd $$PWD;git log -n1 --format=%h_git`\\\" diff --git a/src/tests/testsqlobjects.cpp b/src/tests/testsqlobjects.cpp new file mode 100644 index 00000000..95e2d7b7 --- /dev/null +++ b/src/tests/testsqlobjects.cpp @@ -0,0 +1,72 @@ +#include "../sqlitetypes.h" + +#include + +using namespace sqlb; + +class TestTable: public QObject +{ + Q_OBJECT +private slots: + void sqlOutput(); + void autoincrement(); + void notnull(); +}; + +void TestTable::sqlOutput() +{ + Table tt("testtable"); + Field* f = new Field("id", "integer"); + Field* fkm = new Field("km", "integer", false, "km > 1000"); + tt.addField(f); + tt.addField(new Field("car", "text")); + tt.addField(fkm); + QList pk; + pk.append(f); + pk.append(fkm); + tt.setPrimaryKey(pk); + + QCOMPARE(tt.sql(), QString("CREATE TABLE `testtable` (\n" + "\tid\tinteger,\n" + "\tcar\ttext,\n" + "\tkm\tinteger CHECK(km > 1000),\n" + "\tPRIMARY KEY(id,km)\n" + ")")); +} + +void TestTable::autoincrement() +{ + Table tt("testtable"); + Field* f = new Field("id", "integer"); + Field* fkm = new Field("km", "integer"); + tt.addField(f); + tt.addField(new Field("car", "text")); + tt.addField(fkm); + tt.setPrimaryKey(f, true); + + QCOMPARE(tt.sql(), QString("CREATE TABLE `testtable` (\n" + "\tid\tinteger PRIMARY KEY AUTOINCREMENT,\n" + "\tcar\ttext,\n" + "\tkm\tinteger\n" + ")")); +} + +void TestTable::notnull() +{ + Table tt("testtable"); + Field* f = new Field("id", "integer"); + Field* fkm = new Field("km", "integer"); + tt.addField(f); + tt.addField(new Field("car", "text", true)); + tt.addField(fkm); + tt.setPrimaryKey(f, true); + + QCOMPARE(tt.sql(), QString("CREATE TABLE `testtable` (\n" + "\tid\tinteger PRIMARY KEY AUTOINCREMENT,\n" + "\tcar\ttext NOT NULL,\n" + "\tkm\tinteger\n" + ")")); +} + +QTEST_MAIN(TestTable) +#include "testsqlobjects.moc"