]> Some of my projects - localmylist.git/commitdiff
misc changes
authorAPTX <marek321@gmail.com>
Mon, 17 Nov 2014 07:05:38 +0000 (08:05 +0100)
committerAPTX <marek321@gmail.com>
Mon, 17 Nov 2014 07:05:38 +0000 (08:05 +0100)
16 files changed:
localmylist-management/tabs/dynamicmodeltab.cpp
localmylist.pro
localmylist/dynamicmodel/data.cpp
localmylist/dynamicmodel/datamodel.cpp
localmylist/dynamicmodel/datamodel.h
localmylist/dynamicmodel/model.cpp
localmylist/dynamicmodel/model.h
localmylist/dynamicmodel/query.cpp [new file with mode: 0644]
localmylist/dynamicmodel/query.h [new file with mode: 0644]
localmylist/localmylist.pro
query-test/main.cpp [new file with mode: 0644]
query-test/query-test.pro [new file with mode: 0644]
query-test/queryparser.cpp [new file with mode: 0644]
query-test/queryparser.h [new file with mode: 0644]
query-test/tabledata.cpp [new file with mode: 0644]
query-test/tabledata.h [new file with mode: 0644]

index 493c4e6dc536c88c1bc95f0a2f1e3fb49d60d85b..e016f0523d81a38c50a24fb6c29440ff1eb57be6 100644 (file)
@@ -1,6 +1,8 @@
 #include "dynamicmodeltab.h"
 #include "ui_dynamicmodeltab.h"
 
+#include <QMessageBox>
+
 #include "mainwindow.h"
 #include "database.h"
 #include "mylist.h"
@@ -12,6 +14,8 @@
 #include "dynamicmodel/types.h"
 #include "dynamicmodel/typerelation.h"
 
+#include <QDebug>
+
 using namespace LocalMyList::DynamicModel;
 
 DynamicModelTab::DynamicModelTab(QWidget *parent) :
@@ -59,7 +63,6 @@ void DynamicModelTab::init()
        dataModel->registerTypeRelation(new AnimeAnimeTitleRelation(this));
 
        model = new Model(this);
-       model->setDataModel(dataModel);
 
        myListFilterModel = new MyListFilterModel(this);
        myListFilterModel->setSourceModel(model);
@@ -85,7 +88,14 @@ void DynamicModelTab::init()
 
        connect(model, SIGNAL(queryChanged(QString)), ui->modelQuery, SLOT(setText(QString)));
        //model->setQuery("anime|episode|file|file_location");
-       model->setQuery("anime|episode");
+       Query q(dataModel);
+       q.parse("anime|episode");
+
+       if (!q.isValid()) {
+               qDebug() << "Invalid query" << q.errorString();
+       }
+
+       model->setQuery(q);
 }
 
 void DynamicModelTab::activate()
@@ -185,10 +195,18 @@ void DynamicModelTab::updateSelection()
 
 void DynamicModelTab::on_modelQuery_returnPressed()
 {
-       model->setQuery(ui->modelQuery->text());
+       Query q(dataModel);
+       if (q.parse(ui->modelQuery->text()))
+       {
+               model->setQuery(q);
+       }
+       else
+       {
+               QMessageBox::critical(this, tr("Query parse error"), q.errorString());
+       }
 }
 
 void DynamicModelTab::on_modelQueryButton_clicked()
 {
-       model->setQuery(ui->modelQuery->text());
+       on_modelQuery_returnPressed();
 }
index 7c4ca3657a6c3860b553a2ecb3fa8ec6924b39d2..ab9795b0fb4b234a00a8a1e3f65e965f30cc9296 100644 (file)
@@ -22,3 +22,5 @@ SUBDIRS += localmylist
                SUBDIRS += runscript
        }
 }
+
+SUBDIRS += query-test
index 3fa9e33804d3c1203b9111bfca2f47e06071a4cc..0b060318e5a06964126bf82bab666aaf0313184b 100644 (file)
@@ -51,7 +51,7 @@ void Data::ref(Node *node)
 
 void Data::deref(Node *node)
 {
-       Q_ASSERT(references.isEmpty());
+       Q_ASSERT(!references.isEmpty());
 
        bool removed = references.removeOne(node);
 
index 7e7232df3e032db13f751e7dc04d7eda8213d3e4..3dde9e8c9cb735823051b1d266d4faa82414bd62 100644 (file)
@@ -58,24 +58,46 @@ bool DataModel::registerTypeRelation(TypeRelation *typeRelation)
 DataType *DataModel::dataType(const QString &name) const
 {
        DataType *t = dataTypeNames.value(name, 0);
-       Q_ASSERT(t);
+       Q_ASSERT_X(t, "dynamicmodel", "Unregistered data type requested.");
        return t;
 }
 
+bool DataModel::hasDataType(const QString &name) const
+{
+       return dataTypeNames.value(name, 0);
+}
+
 TypeRelation *DataModel::typeRelation(const QString &source, const QString &destiantion)
 {
        const auto it = typeRelations.find(source);
 
        if (it == typeRelations.constEnd())
+       {
+               Q_ASSERT_X(false, "dynamicmodel", "Unregistered typerelation Requested (source)");
                return 0;
+       }
 
        const auto inner = it.value().find(destiantion);
 
        if (inner == it.value().constEnd())
+       {
+               Q_ASSERT_X(false, "dynamicmodel", "Unregistered typerelation Requested (destination)");
                return 0;
+       }
 
        return inner.value();
 }
 
+bool DataModel::hasTypeRelation(const QString &source, const QString &destiantion) const
+{
+       const auto it = typeRelations.find(source);
+
+       if (it == typeRelations.constEnd())
+               return false;
+
+       const auto inner = it.value().find(destiantion);
+       return inner != it.value().constEnd();
+}
+
 } // namespace DynamicModel
 } // namespace LocalMyList
index 8f589ac4cabdca646292c9e6ee35e17ca2212992..0e42b57c69582e1d04af56e28e7c8ca8d10db466 100644 (file)
@@ -28,7 +28,9 @@ public:
        bool registerTypeRelation(TypeRelation *typeRelation);
 
        DataType *dataType(const QString &name) const;
+       bool hasDataType(const QString &name) const;
        TypeRelation *typeRelation(const QString &source, const QString &destiantion);
+       bool hasTypeRelation(const QString &source, const QString &destiantion) const;
 
 
 
index d55180fb0665b8ab3e2afdffab8ecc637d3d27df..ffa2b9e3b9db8623252722c13f37470f2b3f9a00 100644 (file)
@@ -4,12 +4,15 @@
 #include "datamodel.h"
 #include "datatype.h"
 #include "typerelation.h"
+#include "query.h"
+
+#include <QDebug>
 
 namespace LocalMyList {
 namespace DynamicModel {
 
 Model::Model(QObject *parent) :
-       QAbstractItemModel(parent), m_dataModel(0)
+       QAbstractItemModel(parent)
 {
        rootItem = createRootNode();
 }
@@ -19,21 +22,25 @@ Model::~Model()
        delete rootItem;
 }
 
-QString Model::query() const
+Query Model::query() const
 {
        return m_query;
 }
 
-void Model::setQuery(const QString &query)
+void Model::setQuery(const Query &query)
 {
        if (query == m_query)
                return;
 
-       dataTypeNames = query.split(QChar('|'));
-       reload();
+       if (!query.isValid())
+               return;
 
        m_query = query;
+
+       reload();
+
        emit queryChanged(query);
+       emit queryChanged(query.queryString());
 }
 
 QVariant Model::headerData(int section, Qt::Orientation orientation, int role) const
@@ -162,14 +169,14 @@ QModelIndex Model::index(Node *node) const
        return createIndex(node->row(), 0, node);
 }
 
-DataModel *Model::dataModel() const
+DataType *Model::rootDataType() const
 {
-       return m_dataModel;
+       return m_query.dataModel()->dataType("anime");
 }
 
-DataType *Model::rootDataType() const
+DataModel *Model::dataModel() const
 {
-       return m_dataModel->dataType("anime");
+       return m_query.dataModel();
 }
 
 DataType *Model::grandChildDataType(Node *node) const
@@ -181,9 +188,9 @@ DataType *Model::grandChildDataType(Node *node) const
 
 DataType *Model::childDataType(int i) const
 {
-       if (dataTypeNames.count() <= i)
+       if (m_query.dataTypeNames().count() <= i)
                return 0;
-       return dataModel()->dataType(dataTypeNames.at(i));
+       return dataModel()->dataType(m_query.dataTypeNames().at(i));
 }
 
 void Model::reload()
@@ -194,37 +201,27 @@ void Model::reload()
        endResetModel();
 }
 
-void Model::setDataModel(DataModel *dataModel)
-{
-       if (m_dataModel == dataModel)
-               return;
-
-       m_dataModel = dataModel;
-       emit dataModelChanged(dataModel);
-
-       reload();
-}
-
 void Model::episodeInsert(int aid, int eid)
 {
-       DataType *episodeDataType = m_dataModel->dataType("episode");
+       Q_UNUSED(aid);
+       DataType *episodeDataType = m_query.dataModel()->dataType("episode");
 
        if (!episodeDataType)
                return;
 
-       if (!m_dataModel->dataType("anime"))
+       if (!m_query.dataModel()->dataType("anime"))
                return;
 
        QString previousDataTypeName = QString();
-       DataType *previousDataType = 0;
+//     DataType *previousDataType = 0;
 
-       for (const QString &dataTypeName : dataTypeNames)
+       for (const QString &dataTypeName : m_query.dataTypeNames())
        {
-               DataType *currentDataType = m_dataModel->dataType(dataTypeName);
+               DataType *currentDataType = m_query.dataModel()->dataType(dataTypeName);
 
                if (currentDataType == episodeDataType)
                {
-                       TypeRelation *rel = m_dataModel->typeRelation(previousDataTypeName, dataTypeName);
+                       TypeRelation *rel = m_query.dataModel()->typeRelation(previousDataTypeName, dataTypeName);
 
                        if (previousDataTypeName.isNull())
                        {
@@ -244,12 +241,13 @@ void Model::episodeInsert(int aid, int eid)
 
 Node *Model::createRootNode()
 {
-       int size = (m_dataModel && !dataTypeNames.isEmpty())
-                               ? dataModel()->dataType(dataTypeNames.at(0))->size()
+       int size = (m_query.dataModel() && !m_query.dataTypeNames().isEmpty())
+                               ? dataModel()->dataType(m_query.dataTypeNames().at(0))->size()
                                : 0;
        Node *n = new Node(this, 0, size, 0);
-       if (m_dataModel && !dataTypeNames.isEmpty())
-               n->setChildDataType(dataModel()->dataType(dataTypeNames.at(0)));
+       qDebug() << "SIZE" << size;
+       if (m_query.dataModel() && !m_query.dataTypeNames().isEmpty())
+               n->setChildDataType(dataModel()->dataType(m_query.dataTypeNames().at(0)));
        return n;
 }
 
index 037a329c86afa51817c2aa42ea34789da58541e8..ee4cb6f597c09f02277c6dc0bbe9d3c92e337b4f 100644 (file)
@@ -2,6 +2,7 @@
 #define MODEL_H
 
 #include "../localmylist_global.h"
+#include "query.h"
 #include <QAbstractItemModel>
 #include <QStringList>
 
@@ -11,20 +12,20 @@ namespace DynamicModel {
 class Node;
 class DataModel;
 class DataType;
+class Query;
 
 class LOCALMYLISTSHARED_EXPORT Model : public QAbstractItemModel
 {
        Q_OBJECT
-       Q_PROPERTY(DataModel* dataModel READ dataModel WRITE setDataModel NOTIFY dataModelChanged)
-       Q_PROPERTY(QString query READ query WRITE setQuery NOTIFY queryChanged)
+       Q_PROPERTY(Query query READ query WRITE setQuery NOTIFY queryChanged)
        friend class Node;
 
 public:
        explicit Model(QObject *parent = 0);
        ~Model();
 
-       QString query() const;
-       void setQuery(const QString &query);
+       Query query() const;
+       void setQuery(const Query &query);
 
        QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
        Qt::ItemFlags flags(const QModelIndex &index) const;
@@ -43,9 +44,8 @@ public:
        Node *node(const QModelIndex &idx) const;
        QModelIndex index(Node *node) const;
 
-       DataModel *dataModel() const;
-
        DataType *rootDataType() const;
+       DataModel *dataModel() const;
 
        DataType *grandChildDataType(Node *node) const;
        DataType *childDataType(int i) const;
@@ -53,23 +53,19 @@ public:
 public slots:
        void reload();
 
-       void setDataModel(DataModel *dataModel);
-
 private slots:
        void episodeInsert(int aid, int eid);
 
 signals:
-       void dataModelChanged(DataModel *dataModel);
+       void queryChanged(Query query);
        void queryChanged(QString query);
 
 private:
        Node *createRootNode();
 
        Node *rootItem;
-       DataModel* m_dataModel;
 
-       QStringList dataTypeNames;
-       QString m_query;
+       Query m_query;
 };
 
 } // namespace DynamicModel
diff --git a/localmylist/dynamicmodel/query.cpp b/localmylist/dynamicmodel/query.cpp
new file mode 100644 (file)
index 0000000..5a1626f
--- /dev/null
@@ -0,0 +1,97 @@
+#include "query.h"
+
+#include "datamodel.h"
+
+namespace LocalMyList {
+namespace DynamicModel {
+
+static const QLatin1Literal noDataModel{"No data model"};
+
+Query::Query(DataModel *dataModel) : m_dataModel{dataModel}, m_valid{false}, m_error{NoDataModel},
+       m_errorString{noDataModel}
+{
+
+}
+
+bool Query::parse(const QString &query)
+{
+       if (m_queryString == query)
+               return m_valid;
+
+       m_queryString = query;
+
+       if (!m_dataModel)
+       {
+               m_error = NoDataModel;
+               m_errorString = noDataModel;
+               m_valid = false;
+               return m_valid;
+       }
+
+       QStringList dataTypeNames = query.split(QChar('|'));
+       QString previousDataTypeName;
+       for (auto&& dataTypeName : dataTypeNames)
+       {
+               if (!m_dataModel->hasDataType(dataTypeName))
+               {
+                       m_error = DataTypeError;
+                       m_errorString = QString{"Type \"%1\" not registered in data model"}.arg(dataTypeName);
+                       m_valid = false;
+                       return m_valid;
+               }
+
+               if (!previousDataTypeName.isEmpty()
+                       && !m_dataModel->hasTypeRelation(previousDataTypeName, dataTypeName))
+               {
+                       m_error = TypeRelationError;
+                       m_errorString = QString{"There is no relation registered between type \"%1\" and \"%2\""}
+                                       .arg(previousDataTypeName).arg(dataTypeName);
+                       m_valid = false;
+                       return m_valid;
+               }
+               previousDataTypeName = dataTypeName;
+       }
+       m_dataTypeNames = dataTypeNames;
+       m_error = NoError;
+       m_errorString.clear();
+       m_valid = true;
+       return m_valid;
+}
+
+bool Query::isValid() const
+{
+       return m_valid;
+}
+
+Query::QueryError Query::error() const
+{
+       return m_error;
+}
+
+QString Query::errorString() const
+{
+       return m_errorString;
+}
+
+QString Query::queryString() const
+{
+       return m_queryString;
+}
+
+DataModel *Query::dataModel() const
+{
+       return m_dataModel;
+}
+
+QStringList Query::dataTypeNames() const
+{
+       return m_dataTypeNames;
+}
+
+bool operator ==(const Query &a, const Query& b)
+{
+       return a.m_dataModel == b.m_dataModel && a.m_queryString == b.m_queryString;
+}
+
+} // namespace DynamicModel
+} // namespace LocalMyList
diff --git a/localmylist/dynamicmodel/query.h b/localmylist/dynamicmodel/query.h
new file mode 100644 (file)
index 0000000..3be54e3
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef QUERY_H
+#define QUERY_H
+
+#include "../localmylist_global.h"
+#include <QString>
+#include <QStringList>
+
+namespace LocalMyList {
+namespace DynamicModel {
+
+class DataModel;
+
+class LOCALMYLISTSHARED_EXPORT Query
+{
+public:
+       enum QueryError
+       {
+               NoError,
+               NoDataModel,
+               DataTypeError,
+               TypeRelationError,
+       };
+
+       explicit Query(DataModel *dataModel = 0);
+
+       bool parse(const QString &query);
+
+       bool isValid() const;
+       QueryError error() const;
+       QString errorString() const;
+       QString queryString() const;
+
+       DataModel *dataModel() const;
+       QStringList dataTypeNames() const;
+
+       friend bool operator ==(const Query& a, const Query& b);
+
+private:
+       bool m_valid;
+       QueryError m_error;
+       QString m_errorString;
+       QString m_queryString;
+       DataModel *m_dataModel;
+       QStringList m_dataTypeNames;
+};
+
+} // namespace DynamicModel
+} // namespace LocalMyList
+
+#endif // QUERY_H
index dcb3be5ed63abfd281b5ac5945391973731fba60..e36ade55fb3fe01269dba67a49a5396f6190816d 100644 (file)
@@ -43,7 +43,9 @@ SOURCES += \
        dynamicmodel/datatype.cpp \
        dynamicmodel/types.cpp \
        dynamicmodel/datamodel.cpp \
-       dynamicmodel/typerelation.cpp
+       dynamicmodel/typerelation.cpp \
+    dynamicmodel/query.cpp \
+    dynamicmodel/entry.cpp
 
 HEADERS += \
        localmylist_global.h \
@@ -81,7 +83,9 @@ HEADERS += \
        dynamicmodel/dynamicmodel_global.h \
        dynamicmodel/types.h \
        dynamicmodel/datamodel.h \
-       dynamicmodel/typerelation.h
+       dynamicmodel/typerelation.h \
+    dynamicmodel/query.h \
+    dynamicmodel/entry.h
 
 CONV_HEADERS += \
        include/LocalMyList/AbstractTask \
diff --git a/query-test/main.cpp b/query-test/main.cpp
new file mode 100644 (file)
index 0000000..d62dcca
--- /dev/null
@@ -0,0 +1,39 @@
+#include <QtCore/QCoreApplication>
+
+#include <QStringList>
+#include <QTextStream>
+#include <QUrl>
+#include "mylist.h"
+#include "settings.h"
+#include "queryparser.h"
+
+#include <QDebug>
+
+using namespace LocalMyList;
+
+int main(int argc, char *argv[])
+{
+       QCoreApplication a(argc, argv);
+       QTextStream cout(stdout);
+       if (a.arguments().count() < 2)
+       {
+               cout << "Usage: " << a.arguments()[0] << " QUERY" << endl;
+               return 1;
+       }
+
+       LocalMyList::instance()->loadLocalSettings();
+       if (!LocalMyList::instance()->database()->connect())
+       {
+               cout << "Could not connect to database.";
+               return 1;
+       }
+
+       DataModel d{};
+       QueryParser p{&d};
+
+       bool success = p.parse(a.arguments()[1]);
+
+       qDebug() << "Success" << success;
+
+       return !success;
+}
diff --git a/query-test/query-test.pro b/query-test/query-test.pro
new file mode 100644 (file)
index 0000000..7112bc2
--- /dev/null
@@ -0,0 +1,24 @@
+QT += core
+QT -= gui
+
+include(../config.pri)
+
+TARGET = lml-import-mylist
+DESTDIR = ../build
+#CONFIG += console
+CONFIG -= app_bundle
+
+TEMPLATE = app
+
+SOURCES += main.cpp \
+       queryparser.cpp \
+       tabledata.cpp
+
+include(../localmylist.pri)
+
+target.path = $${PREFIX}/bin
+INSTALLS += target
+
+HEADERS += \
+       queryparser.h \
+       tabledata.h
diff --git a/query-test/queryparser.cpp b/query-test/queryparser.cpp
new file mode 100644 (file)
index 0000000..4a80626
--- /dev/null
@@ -0,0 +1,100 @@
+#include "queryparser.h"
+#include <QStringList>
+#include "tabledata.h"
+//#include "conversions.h"
+
+#include <QDebug>
+
+
+QueryParser::QueryParser(DataModel *dataModel) : m_dataModel{dataModel}, m_valid{false}
+{
+}
+
+bool QueryParser::parse(const QString &rawPath)
+{
+       static const QString emptyString{};
+
+       m_errorString = QString{};
+
+       m_path = rawPath;
+       QStringList parts = m_path.split(QChar('/'), QString::SkipEmptyParts);
+       qDebug() << "parse " << parts;
+
+       m_levels.clear();
+       m_levels.resize(parts.length());
+
+       for (int i = 0; i < parts.length(); ++i) {
+               Level currentLevel;
+
+
+               const QString &part = parts[i];
+
+               const QStringList tableColumn = part.split(QChar('.'));
+               const QString &table = tableColumn[0];
+               const QString &column = tableColumn.size() > 1 ? tableColumn[1] : emptyString;
+
+//             qDebug() << "----------------------- Iteration" << i << "-----------------------";
+               qDebug() << "part(" << part.length() << ") =" << table << "(" << column << ")";
+
+               if (!tables.contains(table)) {
+                       m_errorString = QObject::tr("Table %1 does not exist.").arg(table);
+                       m_valid = false;
+                       return m_valid;
+               } else {
+                       currentLevel.table = table;
+                       currentLevel.type = AnimeEntry;
+               }
+
+               if (!column.isEmpty()) {
+                       if (!table_columns[currentLevel.table].contains(column)) {
+                               m_errorString = QObject::tr("Column %1 does not exist in table %2.")
+                                               .arg(column).arg(table);
+                               m_valid = false;
+                               return m_valid;
+                       }
+               } else {
+                       currentLevel.column = column;
+                       currentLevel.type = ColumnEntry;
+               }
+
+               m_levels.push_back(currentLevel);
+       }
+       m_valid = true;
+       return m_valid;
+}
+
+QString QueryParser::buildQuery(int level)
+{
+       if (!m_valid) return {};
+
+       const Level &lastLevel = level(level);
+
+       QString joins;
+
+       if (lastLevel.column.isEmpty()) {
+               return QString("SELECT %1.%2 FROM %1\n\t%3")
+                               .arg(lastLevel.table).arg(lastLevel.column).arg(joins);
+       }
+}
+
+bool QueryParser::isValid() const
+{
+       return m_valid;
+}
+
+int QueryParser::levels() const
+{
+       return m_levels.count();
+}
+
+const QueryParser::Level &QueryParser::level(int i) const
+{
+       Q_ASSERT_X(i > 0 && m_levels.count() < i, "dynamicmodel/query", "Requestesd invlaid level index");
+       return m_levels[i];
+}
+
+QString QueryParser::path() const
+{
+       return m_path;
+}
+
diff --git a/query-test/queryparser.h b/query-test/queryparser.h
new file mode 100644 (file)
index 0000000..83adc4e
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef QUERYPARSER_H
+#define QUERYPARSER_H
+
+#include <QString>
+#include <QVector>
+#include "dynamicmodel/datamodel.h"
+
+using namespace LocalMyList::DynamicModel;
+
+class QueryParser
+{
+public:
+       enum EntryType {
+               ColumnEntry,
+               AnimeEntry,
+               EpisodeEntry,
+               FileEntry,
+       };
+
+       struct Level {
+               EntryType type;
+               QString table;
+               QString column;
+       };
+
+       QueryParser(DataModel *dataModel = 0);
+
+       bool parse(const QString &rawPath);
+
+       QString buildQuery(int level);
+
+       bool isValid() const;
+       int levels() const;
+       const Level &level(int i) const;
+
+       QString path() const;
+
+private:
+       bool m_valid;
+       QString m_path;
+       QString m_errorString;
+       QVector<Level> m_levels;
+       DataModel *m_dataModel;
+
+};
+
+#endif // QUERYPARSER_H
diff --git a/query-test/tabledata.cpp b/query-test/tabledata.cpp
new file mode 100644 (file)
index 0000000..e88aa33
--- /dev/null
@@ -0,0 +1,123 @@
+#include "tabledata.h"
+
+namespace Token {
+const QLatin1String AnimeTable{"anime"};
+const QLatin1String EpisodeTable{"episode"};
+const QLatin1String FileTable{"file"};
+const QLatin1String Entries{"entries"};
+const QLatin1String Metadata{"metadata"};
+const QLatin1String FirstUnwatched{"fisrt_unwatched"};
+const QLatin1String BestFile{"best_file"};
+const QLatin1String BestLocation{"best_location"};
+}
+
+// TODO all of these shouldbe generated.
+const QStringList tables = QStringList()
+// TODO anime_title is currently not supported
+//             << "anime_title"
+               << "anime"
+               << "episode"
+               << "file";
+
+const QMap<QString, QString> table_main_column = []() {
+       QMap<QString, QString> r;
+       r["anime"] = "title_romaji";
+       r["episode"] = "title_english";
+       r["file"] = "fid";
+       return r;
+}();
+
+const QMap<QString, QStringList> table_columns = []() {
+       QMap<QString, QStringList> r;
+       r["anime"] = QStringList()
+               << "aid"
+               << "entry_added"
+               << "anidb_update"
+               << "entry_update"
+               << "my_update"
+               << "title_english"
+               << "title_romaji"
+               << "title_kanji"
+               << "description"
+               << "year"
+               << "start_date"
+               << "end_date"
+               << "type"
+               << "total_episode_count"
+               << "highest_epno"
+               << "rating"
+               << "votes"
+               << "temp_rating"
+               << "temp_votes"
+               << "my_vote"
+               << "my_vote_date"
+               << "my_temp_vote"
+               << "my_temp_vote_date";
+       r["episode"] = QStringList()
+               << "eid"
+               << "aid"
+               << "entry_added"
+               << "anidb_update"
+               << "entry_update"
+               << "my_update"
+               << "epno"
+               << "title_english"
+               << "title_romaji"
+               << "title_kanji"
+               << "length"
+               << "airdate"
+               << "state"
+               << "type"
+               << "recap"
+               << "rating"
+               << "votes"
+               << "my_vote"
+               << "my_vote_date";
+       r["file"] = QStringList()
+               << "fid"
+               << "eid"
+               << "aid"
+               << "gid"
+               << "lid"
+               << "entry_added"
+               << "anidb_update"
+               << "entry_update"
+               << "my_update"
+               << "ed2k"
+               << "size"
+               << "length"
+               << "extension"
+               << "group_name"
+               << "group_name_short"
+               << "crc"
+               << "release_date"
+               << "version"
+               << "censored"
+               << "deprecated"
+               << "source"
+               << "quality"
+               << "resolution"
+               << "video_codec"
+               << "audio_codec"
+               << "audio_language"
+               << "subtitle_language"
+               << "aspect_ratio"
+               << "my_watched"
+               << "my_state"
+               << "my_file_state"
+               << "my_storage"
+               << "my_source"
+               << "my_other";
+       return r;
+}();
+
+const QMap<QString, QMap<QString, QString>> join_map = []() {
+       QMap<QString, QMap<QString, QString>> r;
+       r["anime"]["episode"] = "anime.aid = episode.aid";
+       r["anime"]["file"] = "anime.aid = file.aid";
+       r["episode"]["file"] = "episode.eid = file.eid";
+       r["episode"]["anime"] = "episode.aid = anime.aid";
+       r["file"]["anime"] = "file.aid = anime.aid";
+       r["file"]["episode"] = "file.eid = episode.eid";
+       return r;
+}();
diff --git a/query-test/tabledata.h b/query-test/tabledata.h
new file mode 100644 (file)
index 0000000..d055d7b
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef TABLEDATA_H
+#define TABLEDATA_H
+
+#include <QMap>
+#include <QStringList>
+#include <QString>
+
+namespace Token {
+extern const QLatin1String AnimeTable;
+extern const QLatin1String EpisodeTable;
+extern const QLatin1String FileTable;
+extern const QLatin1String Entries;
+extern const QLatin1String Metadata;
+extern const QLatin1String FirstUnwatched;
+extern const QLatin1String BestFile;
+extern const QLatin1String BestLocation;
+}
+
+extern const QStringList tables;
+extern const QMap<QString, QStringList> table_columns;
+extern const QMap<QString, QString> table_main_column;
+extern const QMap<QString, QMap<QString, QString>> join_map;
+
+#endif // TABLEDATA_H