commit 3160499ccda0138accf32cef2b9478b2a7dc6bd3
Author: Christian Ehringfeld <c.ehringfeld@t-online.de>
Date:   Thu Aug 6 18:20:51 2015 +0200

    queryinterpreter/builder wip

diff --git a/EntityManager.pro b/EntityManager.pro
index d34fa4d..38be334 100644
--- a/EntityManager.pro
+++ b/EntityManager.pro
@@ -28,7 +28,9 @@ src/entity.h \
     src/query.h \
     src/join.h \
     src/queryinterpreter.h \
-    src/condition.h
+    src/condition.h \
+    src/expression.h \
+    src/orderby.h
 
 SOURCES += \
 src/entity.cpp \
@@ -50,7 +52,9 @@ src/entity.cpp \
     src/query.cpp \
     src/join.cpp \
     src/queryinterpreter.cpp \
-    src/condition.cpp
+    src/condition.cpp \
+    src/expression.cpp \
+    src/orderby.cpp
 
 unix {
     target.path = /usr/lib
diff --git a/src/expression.cpp b/src/expression.cpp
new file mode 100644
index 0000000..e1dc7bc
--- /dev/null
+++ b/src/expression.cpp
@@ -0,0 +1,31 @@
+#include "expression.h"
+using namespace CuteEntityManager;
+Expression::Expression() {
+}
+
+Expression::Expression(QString expression,
+                       bool onlyColumn) {
+    this->expression = expression;
+    this->onlyColumn = onlyColumn;
+}
+
+QString Expression::getExpression() const {
+    return this->expression;
+}
+
+void Expression::setExpression(const QString &value) {
+    this->expression = value;
+}
+
+QString Expression::toString() const {
+    return this->expression;
+}
+
+bool Expression::getOnlyColumn() const {
+    return onlyColumn;
+}
+
+void Expression::setOnlyColumn(bool value) {
+    onlyColumn = value;
+}
+
diff --git a/src/expression.h b/src/expression.h
new file mode 100644
index 0000000..affedab
--- /dev/null
+++ b/src/expression.h
@@ -0,0 +1,26 @@
+#ifndef EXPRESSION_H
+#define EXPRESSION_H
+
+#include <QHash>
+#include <QString>
+#include <QVariant>
+namespace CuteEntityManager {
+class Expression {
+  public:
+    Expression();
+    Expression(QString expression,
+               bool onlyColumn = false);
+    QString getExpression() const;
+    void setExpression(const QString &value);
+
+    QString toString() const;
+
+    bool getOnlyColumn() const;
+    void setOnlyColumn(bool value);
+
+  private:
+    QString expression;
+    bool onlyColumn;
+};
+}
+#endif // EXPRESSION_H
diff --git a/src/join.cpp b/src/join.cpp
index 31c2154..4b29cb3 100644
--- a/src/join.cpp
+++ b/src/join.cpp
@@ -5,6 +5,12 @@ Join::Join() {
 }
 
 Join::Join(QString foreignTable, QString condition, QString type) {
+    this->foreignTable = foreignTable;
+    this->condition = Condition(condition);
+    this->type = type;
+}
+
+Join::Join(QString foreignTable, Condition condition, QString type) {
     this->foreignTable = foreignTable;
     this->condition = condition;
     this->type = type;
@@ -26,12 +32,20 @@ void Join::setForeignTable(const QString &value) {
     foreignTable = value;
 }
 
-QString Join::getCondition() const {
+Condition Join::getCondition() const {
     return condition;
 }
 
-void Join::setCondition(const QString &value) {
-    condition = value;
+QString Join::getMainCondition() const {
+    auto conditions = this->condition.getConditions();
+    if (!conditions.isEmpty()) {
+        return conditions.at(0);
+    } else {
+        return "";
+    }
 }
 
+void Join::setCondition(const Condition &value) {
+    condition = value;
+}
 
diff --git a/src/join.h b/src/join.h
index f9ece86..c8213fe 100644
--- a/src/join.h
+++ b/src/join.h
@@ -1,13 +1,14 @@
 #ifndef JOIN_H
 #define JOIN_H
 #include <QString>
-
+#include "condition.h"
 namespace CuteEntityManager {
 class Join {
-
   public:
     Join();
-    Join(QString foreignTable, QString condition,
+    explicit Join(QString foreignTable, QString condition,
+         QString type = QStringLiteral("LEFT JOIN"));
+    explicit Join(QString foreignTable, Condition condition,
          QString type = QStringLiteral("LEFT JOIN"));
 
     QString getType() const;
@@ -16,13 +17,14 @@ class Join {
     QString getForeignTable() const;
     void setForeignTable(const QString &value);
 
-    QString getCondition() const;
-    void setCondition(const QString &value);
+    Condition getCondition() const;
+    QString getMainCondition() const;
+    void setCondition(const Condition &value);
 
-  private:
+private:
     QString type = QStringLiteral("LEFT JOIN");
     QString foreignTable;
-    QString condition;
+    Condition condition;
 
 };
 }
diff --git a/src/orderby.cpp b/src/orderby.cpp
new file mode 100644
index 0000000..11b23a8
--- /dev/null
+++ b/src/orderby.cpp
@@ -0,0 +1,40 @@
+#include "orderby.h"
+using namespace CuteEntityManager;
+OrderBy::OrderBy() {
+    this->direction = Direction::DEFAULT;
+}
+
+OrderBy::OrderBy(QString column, Direction direction) {
+    this->column = column;
+    this->direction = direction;
+}
+
+OrderBy::OrderBy(Expression direction) {
+    this->column = "";
+    this->expressedDirection = direction;
+}
+
+QString OrderBy::getColumn() const {
+    return column;
+}
+
+void OrderBy::setColumn(const QString &value) {
+    column = value;
+}
+
+Direction OrderBy::getDirection() const {
+    return direction;
+}
+
+void OrderBy::setDirection(const Direction &value) {
+    direction = value;
+}
+
+Expression OrderBy::getExpressedDirection() const {
+    return expressedDirection;
+}
+
+void OrderBy::setExpressedDirection(const Expression &value) {
+    expressedDirection = value;
+}
+
diff --git a/src/orderby.h b/src/orderby.h
new file mode 100644
index 0000000..f5ae316
--- /dev/null
+++ b/src/orderby.h
@@ -0,0 +1,34 @@
+#ifndef ORDERBY_H
+#define ORDERBY_H
+
+#include <QString>
+#include "expression.h"
+namespace CuteEntityManager {
+enum class Direction {
+    SORT_ASC,
+    SORT_DESC,
+    DEFAULT
+};
+
+//class Expression;
+class OrderBy {
+  public:
+    OrderBy();
+    OrderBy(QString column, Direction direction = Direction::DEFAULT);
+    OrderBy(Expression direction);
+    QString getColumn() const;
+    void setColumn(const QString &value);
+
+    Direction getDirection() const;
+    void setDirection(const Direction &value);
+
+    Expression getExpressedDirection() const;
+    void setExpressedDirection(const Expression &value);
+
+  private:
+    QString column;
+    Direction direction;
+    Expression expressedDirection;
+};
+}
+#endif // ORDERBY_H
diff --git a/src/query.cpp b/src/query.cpp
index 28abd44..0d05b2d 100644
--- a/src/query.cpp
+++ b/src/query.cpp
@@ -1,32 +1,25 @@
 #include "query.h"
 #include "condition.h"
+#include "orderby.h"
 using namespace CuteEntityManager;
 Query::Query() {
-    this->select << "*";
+    //this->select << Expression("*");
 }
 
-QStringList Query::getSelect() const {
-    return select;
+void Query::appendWhereCondition(const QString &condition) {
+    this->where.append(Condition(condition));
 }
 
-void Query::appendCondition(const QString &condition) {
-    this->conditions.append(Condition(condition));
-}
-
-void Query::appendCondition(const Condition &condition) {
-    this->conditions.append(condition);
-}
-QLinkedList<Condition> Query::getConditions() const {
-    return conditions;
-}
-
-void Query::setConditions(const QLinkedList<Condition> &value) {
-    conditions = value;
+void Query::appendWhereCondition(const Condition &condition) {
+    this->where.append(condition);
 }
 
 void Query::setSelect(const QStringList &value) {
-    select = value;
+    for (int var = 0; var < value.size(); ++var) {
+        this->appendSelect(value.at(var));
+    }
 }
+
 QString Query::getSelectOption() const {
     return selectOption;
 }
@@ -34,6 +27,7 @@ QString Query::getSelectOption() const {
 void Query::setSelectOption(const QString &value) {
     selectOption = value;
 }
+
 bool Query::getDistinct() const {
     return distinct;
 }
@@ -41,6 +35,7 @@ bool Query::getDistinct() const {
 void Query::setDistinct(bool value) {
     distinct = value;
 }
+
 QStringList Query::getFrom() const {
     return from;
 }
@@ -48,6 +43,7 @@ QStringList Query::getFrom() const {
 void Query::setFrom(const QStringList &value) {
     from = value;
 }
+
 QStringList Query::getGroupBy() const {
     return groupBy;
 }
@@ -55,13 +51,15 @@ QStringList Query::getGroupBy() const {
 void Query::setGroupBy(const QStringList &value) {
     groupBy = value;
 }
-QStringList Query::getOrderBy() const {
-    return orderBy;
+
+void Query::appendSelect(const Expression &value) {
+    this->select.append(value);
 }
 
-void Query::setOrderBy(const QStringList &value) {
-    orderBy = value;
+void Query::appendSelect(const QString &value) {
+    this->select.append(Expression(value, true));
 }
+
 QList<Join> Query::getJoins() const {
     return joins;
 }
@@ -97,3 +95,43 @@ uint Query::getOffset() const {
 void Query::setOffset(const uint &value) {
     offset = value;
 }
+
+void Query::appendHavingCondition(const QString &condition) {
+    this->having.append(Condition(condition));
+}
+
+void Query::appendHavingCondition(const Condition &condition) {
+    this->having.append(condition);
+}
+
+QList<Condition> Query::getWhere() const {
+    return where;
+}
+
+void Query::setWhere(const QList<Condition> &value) {
+    where = value;
+}
+
+QList<Condition> Query::getHaving() const {
+    return having;
+}
+
+void Query::setHaving(const QList<Condition> &value) {
+    having = value;
+}
+
+void Query::appendOrderBy(const OrderBy &orderBy) {
+    this->orderBy.append(orderBy);
+}
+
+void Query::appendOrderBy(const QString &column, const Direction &direction) {
+    this->orderBy.append(OrderBy(column, direction));
+}
+
+QList<OrderBy> Query::getOrderBy() const {
+    return orderBy;
+}
+
+void Query::setOrderBy(const QList<OrderBy> &value) {
+    orderBy = value;
+}
diff --git a/src/query.h b/src/query.h
index b187387..e2c532a 100644
--- a/src/query.h
+++ b/src/query.h
@@ -5,14 +5,15 @@
 #include <QVariant>
 #include <QLinkedList>
 #include "join.h"
+#include "expression.h"
 
 namespace CuteEntityManager {
 class Condition;
+class OrderBy;
+enum class Direction;
 class Query {
   public:
     Query();
-    QStringList getSelect() const;
-    void setSelect(const QStringList &value);
 
     QString getSelectOption() const;
     void setSelectOption(const QString &value);
@@ -23,12 +24,6 @@ class Query {
     QStringList getFrom() const;
     void setFrom(const QStringList &value);
 
-    QStringList getGroupBy() const;
-    void setGroupBy(const QStringList &value);
-
-    QStringList getOrderBy() const;
-    void setOrderBy(const QStringList &value);
-
     QList<Join> getJoins() const;
     void setJoins(const QList<Join> &value);
 
@@ -42,19 +37,41 @@ class Query {
     uint getOffset() const;
     void setOffset(const uint &value);
 
-    void appendCondition(const QString &condition);
-    void appendCondition(const Condition &condition);
-    QLinkedList<Condition> getConditions() const;
-    void setConditions(const QLinkedList<Condition> &value);
+    void appendWhereCondition(const QString &condition);
+    void appendWhereCondition(const Condition &condition);
+
+    void appendHavingCondition(const QString &condition);
+    void appendHavingCondition(const Condition &condition);
+
+    QList<Condition> getWhere() const;
+    void setWhere(const QList<Condition> &value);
+
+    QList<Condition> getHaving() const;
+    void setHaving(const QList<Condition> &value);
+
+    void appendOrderBy(const OrderBy &orderBy);
+    void appendOrderBy(const QString &column, const Direction &direction);
+    QList<OrderBy> getOrderBy() const;
+    void setOrderBy(const QList<OrderBy> &value);
+
+    QStringList getGroupBy() const;
+    void setGroupBy(const QStringList &value);
+
+    QList<Expression> getSelect() const;
+    void appendSelect(const Expression &value);
+    void appendSelect(const QString &value);
+    void setSelect(const QList<Expression> &value);
+    void setSelect(const QStringList &value);
 
-  private:
-    QStringList select;
+private:
+    QList<Expression> select;
     QString selectOption = QStringLiteral("");
     bool distinct = false;
     QStringList from;
     QStringList groupBy;
-    QStringList orderBy;
-    QLinkedList<Condition> conditions;
+    QList<OrderBy> orderBy;
+    QList<Condition> where;
+    QList<Condition> having;
     QList<Join> joins;
     QHash<QString, QVariant> params;
     uint limit = 0;
diff --git a/src/querybuilder.cpp b/src/querybuilder.cpp
index 7d79977..e780b41 100644
--- a/src/querybuilder.cpp
+++ b/src/querybuilder.cpp
@@ -27,6 +27,7 @@ QueryBuilder::QueryBuilder(QSharedPointer<Schema> schema,
                            QSharedPointer<Database> database) {
     this->schema = schema;
     this->database = database;
+    this->separator = " ";
 }
 
 QueryBuilder::~QueryBuilder() {
@@ -893,7 +894,24 @@ QString QueryBuilder::entityClassname() const {
     return QString("CuteEntityManager::Entity");
 }
 
-QString QueryBuilder::limit(const qint64 &limit, const qint64 &offset) const {
+QStringList QueryBuilder::quoteTableNames(const QStringList &tables) {
+    QStringList r = QStringList();
+    for (int i = 0; i < tables.size(); ++i) {
+        r.append(this->schema->quoteTableName(tables.at(i)));
+    }
+    return r;
+}
+
+QString QueryBuilder::getSeparator() const {
+    return separator;
+}
+
+void QueryBuilder::setSeparator(const QString &value) {
+    separator = value;
+}
+
+
+QString QueryBuilder::limit(const quint64 &limit, const quint64 &offset) const {
     QString s = "";
     if (limit > 0) {
         s.append(" " + this->limitKeyword() + " ").append(QString::number(limit));
@@ -1160,39 +1178,40 @@ void QueryBuilder::andOperator(Query &query,
                      this->placeHolder(var.key());
         query.appendParam(var.key(), var.value());
     }
-    query.appendCondition(condition);
+    query.appendWhereCondition(condition);
 }
 
 void QueryBuilder::arbitraryOperator(Query &query, QString op, QString column,
                                      QVariant value) {
-    query.appendCondition(this->schema->quoteColumnName(column) + " " + op + " " +
-                          this->placeHolder(column));
+    query.appendWhereCondition(this->schema->quoteColumnName(
+                                   column) + " " + op + " " +
+                               this->placeHolder(column));
     query.appendParam(column, value);
 }
 
 void QueryBuilder::isNull(Query &query, QString column) {
-    query.appendCondition(this->schema->quoteColumnName(column) + " IS NULL");
+    query.appendWhereCondition(this->schema->quoteColumnName(column) + " IS NULL");
 }
 
 void QueryBuilder::isNotNull(Query &query, QString column) {
-    query.appendCondition(this->schema->quoteColumnName(column) + " IS " +
-                          this->notKeyword() + " NULL");
+    query.appendWhereCondition(this->schema->quoteColumnName(column) + " IS " +
+                               this->notKeyword() + " NULL");
 }
 
 void QueryBuilder::plainOr(Query &query) {
-    query.appendCondition(this->orKeyword());
+    query.appendWhereCondition(this->orKeyword());
 }
 
 void QueryBuilder::plainNor(Query &query) {
-    query.appendCondition(this->notKeyword() + " " + this->orKeyword());
+    query.appendWhereCondition(this->notKeyword() + " " + this->orKeyword());
 }
 
 void QueryBuilder::plainAnd(Query &query) {
-    query.appendCondition(this->andKeyword());
+    query.appendWhereCondition(this->andKeyword());
 }
 
 void QueryBuilder::plainNand(Query &query) {
-    query.appendCondition(this->notKeyword() + " " +  this->andKeyword());
+    query.appendWhereCondition(this->notKeyword() + " " +  this->andKeyword());
 }
 
 void QueryBuilder::like(Query &query, QString column, QVariant value,
@@ -1220,14 +1239,14 @@ void QueryBuilder::like(Query &query, QHash<QString, QVariant> conditions,
             query.appendParam(i.key(), newVal.isEmpty() ? i.value() : newVal);
         }
         condition += ")";
-        query.appendCondition(condition);
+        query.appendWhereCondition(condition);
     }
 }
 
 void QueryBuilder::where(Query &query, QString column, QVariant value) {
     QString placeholder = column + "_where";
-    query.appendCondition(this->schema->quoteColumnName(column) + "=" +
-                          this->placeHolder(placeholder));
+    query.appendWhereCondition(this->schema->quoteColumnName(column) + "=" +
+                               this->placeHolder(placeholder));
     query.appendParam(placeholder, value);
 }
 
@@ -1237,12 +1256,12 @@ void QueryBuilder::where(Query &query, QHash<QString, QVariant> conditions,
     for (auto i = conditions.constBegin(); i != conditions.constEnd(); ++i) {
         query.appendParam(i.key(), i.value());
     }
-    query.appendCondition(condition);
+    query.appendWhereCondition(condition);
 }
 
 void QueryBuilder::where(Query &query, QString condition,
                          QHash<QString, QVariant> values) {
-    query.appendCondition(condition);
+    query.appendWhereCondition(condition);
     for (auto i = values.constBegin(); i != values.constEnd(); ++i) {
         query.appendParam(i.key(), i.value());
     }
@@ -1269,16 +1288,16 @@ void QueryBuilder::appendCondition(Query &q, QString ph1, QString ph2,
                                    QVariant val1, QVariant val2, QString condition) {
     q.appendParam(ph1, val1);
     q.appendParam(ph2, val2);
-    q.appendCondition(condition);
+    q.appendWhereCondition(condition);
 }
 
 void QueryBuilder::in(Query &query, QString column, QList<QVariant> values) {
-    query.appendCondition(this->inFunction(query, column, values));
+    query.appendWhereCondition(this->inFunction(query, column, values));
 }
 
 void QueryBuilder::notIn(Query &query, QString column, QList<QVariant> values) {
-    query.appendCondition(this->inFunction(query, column,
-                                           values, true));
+    query.appendWhereCondition(this->inFunction(query, column,
+                               values, true));
 }
 
 void QueryBuilder::orOperator(Query &query,
@@ -1298,7 +1317,7 @@ void QueryBuilder::orOperator(Query &query,
             query.appendParam(i.key(), i.value());
         }
         condition += ")";
-        query.appendCondition(condition);
+        query.appendWhereCondition(condition);
     }
 }
 
diff --git a/src/querybuilder.h b/src/querybuilder.h
index f452ca9..c8e9e6c 100644
--- a/src/querybuilder.h
+++ b/src/querybuilder.h
@@ -42,6 +42,7 @@ class QueryBuilder {
      * EntityManager is a friend class, cause we want a light public api.
      */
     friend class EntityManager;
+    friend class QueryInterpreter;
   public:
     QueryBuilder(QSharedPointer<Schema> schema, QSharedPointer<Database> database);
     virtual ~QueryBuilder();
@@ -158,6 +159,10 @@ class QueryBuilder {
               QString conjunction = "AND",
               JokerPosition jp = JokerPosition::BOTH, QChar wildcard = '%');
 
+    QStringList quoteTableNames(const QStringList &tables);
+    QString getSeparator() const;
+    void setSeparator(const QString &value);
+
   protected:
     class ClassAttributes {
       public:
@@ -215,7 +220,7 @@ class QueryBuilder {
                      const QString &primaryKey = "id") const;
     QList<QSqlQuery> createOrMerge(const QSharedPointer<Entity> &entity,
                                    bool insert) const;
-    virtual QString limit(const qint64 &limit, const qint64 &offset) const;
+    virtual QString limit(const quint64 &limit, const quint64 &offset) const;
     QString generateIndexName(const QString &name, const QString &table,
                               const QString &refColumn, const QString &refTable, const bool fk) const;
     QString generateColumnNameID(QString name) const;
@@ -292,7 +297,7 @@ class QueryBuilder {
     virtual void appendCondition(Query &q, QString ph1, QString ph2, QVariant val1,
                                  QVariant val2, QString condition);
     QString entityClassname() const;
-
+    QString separator;
     QSharedPointer<Schema> schema;
     QSharedPointer<Database> database;
 };
diff --git a/src/queryinterpreter.cpp b/src/queryinterpreter.cpp
index ae6e185..fb3251a 100644
--- a/src/queryinterpreter.cpp
+++ b/src/queryinterpreter.cpp
@@ -1,4 +1,11 @@
 #include "queryinterpreter.h"
+#include "condition.h"
+#include "join.h"
+#include "query.h"
+#include "querybuilder.h"
+#include "orderby.h"
+#include "expression.h"
+#include "schema.h"
 using namespace CuteEntityManager;
 
 
@@ -6,6 +13,194 @@ QueryInterpreter::QueryInterpreter(QSharedPointer<QueryBuilder> builder) {
     this->builder = builder;
 }
 
-QSqlQuery QueryInterpreter::interpretQuery(Query &q) {
+QSqlQuery QueryInterpreter::build(const Query &q) {
+    QList<QString> clauses = QList<QString>();
+    clauses.append(this->buildSelect(q.getSelect(), q.getDistinct(),
+                                     q.getSelectOption()));
+    clauses.append(this->buildFrom(q.getFrom()));
+    clauses.append(this->buildJoin(q.getJoins()));
+    clauses.append(this->buildWhere(q.getWhere()));
+    clauses.append(this->buildGroupBy(q.getGroupBy()));
+    clauses.append(this->buildHaving(q.getHaving()));
+    QString sql = "";
+    bool first = true;
+    for (int i = 0; i < clauses.size(); ++i) {
+        QString clause = clauses.at(i);
+        if (!clause.isEmpty()) {
+            if (first) {
+                first = false;
+            } else {
+                sql += this->builder->getSeparator();
+            }
+            sql += clause;
+        }
+    }
+    sql = this->buildOrderByAndLimit(sql, q.getOrderBy(), q.getLimit(),
+                                     q.getOffset());
+    QSqlQuery sqlQuery = this->builder->getQuery();
+    sqlQuery.prepare(sql);
+    this->builder->bindValues(q.getParams(), sqlQuery, false);
+    return sqlQuery;
+}
+
+QString QueryInterpreter::buildSelect(const QList<Expression> &columns,
+                                      const bool &distinct, const QString &selectOption) const {
+    QString sqlSelect = distinct ? "SELECT DISTINCT" : "SELECT";
+    if (!selectOption.isEmpty()) {
+        sqlSelect += this->builder->getSeparator() + selectOption;
+    }
+    if (columns.isEmpty()) {
+        return sqlSelect + " *";
+    }
+    bool first = true;
+    for (int i = 0; i < columns.size(); ++i) {
+        if (first) {
+            first = false;
+        } else {
+            sqlSelect += ", ";
+        }
+        Expression e = columns.at(i);
+        QString nExp = e.getExpression();
+        if (e.getOnlyColumn()) {
+            sqlSelect += this->builder->getSchema()->quoteColumnName(e.getExpression());
+        } else if (!nExp.contains("(")) {
+            QRegularExpression re =
+                QRegularExpression(
+                    QRegularExpression::escape("/^(.*?)(?i:\\s+as\\s+|\\s+)([\\w\\-_\\.]+)$/"));
+            re.optimize();
+            QRegularExpressionMatchIterator iterator = re.globalMatch(nExp, 0,
+                    QRegularExpression::PartialPreferFirstMatch);
+
+            if (iterator.hasNext()) {
+                for (int var = 0; var < 2; ++var) {
+                    QRegularExpressionMatch match = iterator.next();
+                    if (var == 1) {
+                        sqlSelect += this->builder->getSchema()->quoteColumnName(
+                                         match.captured()) + " AS " + this->builder->getSchema()->quoteColumnName("a" +
+                                                 QString::number(i));
+                    }
+                }
+
+            } else {
+                nExp = this->builder->getSchema()->quoteColumnName(nExp);
+            }
+        } else {
+            sqlSelect += nExp + " AS " + this->builder->getSchema()->quoteColumnName("a" +
+                         QString::number(i));
+        }
+    }
+    return sqlSelect;
+}
+
+QString QueryInterpreter::buildFrom(const QStringList &from) const {
+    if (from.isEmpty()) {
+        return "";
+    }
+    auto tables = this->builder->quoteTableNames(from);
+    QString clause = "FROM ";
+    bool first = true;
+    for (int var = 0; var < tables.size(); ++var) {
+        if (first) {
+            first = false;
+        } else {
+            clause += ", ";
+        }
+        clause += from.at(var);
+    }
+    return clause;
+}
+
+QString QueryInterpreter::buildJoin(const QList<Join> &joins) const {
+    if (joins.isEmpty()) {
+        return "";
+    }
+    QString sqlJoin = "";
+    for (int i = 0; i < joins.size(); ++i) {
+        Join j = joins.at(i);
+        sqlJoin += j.getType() + this->builder->getSeparator() +
+                   this->builder->getSchema()->quoteTableName(j.getForeignTable());
+        if (!j.getCondition().getConditions().isEmpty()) {
+            QString condition = this->buildCondition(j.getCondition());
+            if (!condition.isEmpty()) {
+                sqlJoin += " ON " + condition;
+            }
+        }
+    }
+    return sqlJoin;
+}
+
+QString QueryInterpreter::buildWhere(const QList<Condition> &conditions)
+const {
+    QString where = this->buildCondition(conditions);
+    return where.isEmpty() ? "" : ("WHERE " + where);
+}
 
+QString QueryInterpreter::buildGroupBy(const QStringList &groupBy) const {
+    return groupBy.isEmpty() ? "" : "GROUP BY " + this->builder->buildColumns(
+               groupBy);
 }
+
+QString QueryInterpreter::buildHaving(const QList<Condition> &conditions)
+const {
+    QString having = this->buildCondition(conditions);
+    return having.isEmpty() ? "" : ("HAVING " + having);
+}
+
+QString QueryInterpreter::buildOrderByAndLimit(QString sql,
+        const QList<OrderBy> &orderBy, const quint64 &limit,
+        const quint64 &offset) const {
+    QString sqlOrderBy = this->buildOrderBy(orderBy);
+    if (!sqlOrderBy.isEmpty()) {
+        sql += this->builder->getSeparator() + sqlOrderBy;
+    }
+    QString sqlLimit = this->builder->limit(limit, offset);
+    if (!sqlLimit.isEmpty()) {
+        sql += this->builder->getSeparator() + sqlLimit;
+    }
+    return sql;
+}
+
+QString QueryInterpreter::buildOrderBy(const QList<OrderBy> &columns) const {
+    if (columns.isEmpty()) {
+        return "";
+    }
+    bool first = true;
+    QString sqlOrder = "ORDER BY ";
+    for (int i = 0; i < columns.size(); ++i) {
+        if (first) {
+            first = false;
+        } else {
+            sqlOrder += ", ";
+        }
+        OrderBy order = columns.at(i);
+        if (order.getColumn().isEmpty()) {
+            sqlOrder += order.getExpressedDirection().getExpression();
+        } else {
+            sqlOrder += this->builder->getSchema()->quoteColumnName(order.getColumn());
+            switch (order.getDirection()) {
+            case Direction::SORT_ASC:
+                sqlOrder += " ASC";
+                break;
+            case Direction::SORT_DESC:
+                sqlOrder += " DESC";
+                break;
+            default:
+                break;
+            }
+        }
+    }
+    return sqlOrder;
+}
+
+QString QueryInterpreter::buildCondition(const QList<Condition> &conditions)
+const {
+    if (conditions.isEmpty()) {
+        return "";
+    }
+    return "";
+}
+
+QString QueryInterpreter::buildCondition(const Condition &conditions) const {
+    return "";
+}
+
diff --git a/src/queryinterpreter.h b/src/queryinterpreter.h
index e2e5ed2..6d1d1d0 100644
--- a/src/queryinterpreter.h
+++ b/src/queryinterpreter.h
@@ -3,16 +3,72 @@
 
 #include <QSqlQuery>
 #include <QSharedPointer>
+#include <QRegularExpressionMatchIterator>
 namespace CuteEntityManager {
 class Query;
 class QueryBuilder;
+class Condition;
+class Join;
+class OrderBy;
+class Expression;
 class QueryInterpreter {
   public:
     QueryInterpreter(QSharedPointer<QueryBuilder> builder);
-    QSqlQuery interpretQuery(Query &q);
+    QSqlQuery build(const Query &q);
+
+  protected:
+    QString buildSelect(const QList<Expression> &columns, const bool &distinct = false,
+                        const QString &selectOption = "") const;
+    QString buildFrom(const QStringList &from) const;
+    QString buildJoin(const QList<Join> &joins) const;
+    QString buildWhere(const QList<Condition> &conditions) const;
+    QString buildGroupBy(const QStringList &groupBy) const;
+    QString buildHaving(const QList<Condition> &conditions) const;
+    QString buildOrderByAndLimit(QString sql, const QList<OrderBy> &orderBy,
+                                 const quint64 &limit, const quint64 &offset) const;
+    QString buildOrderBy(const QList<OrderBy> &columns) const;
+    QString buildCondition(const QList<Condition> &conditions) const;
+    QString buildCondition(const Condition &conditions) const;
+
   private:
     QSharedPointer<QueryBuilder> builder;
+
 };
+
+
+
+
+//QStringList select;
+//QString selectOption = QStringLiteral("");
+//bool distinct = false;
+//QStringList from;
+//QStringList groupBy;
+//QStringList orderBy;
+//QLinkedList<Condition> conditions;
+//QList<Join> joins;
+//QHash<QString, QVariant> params;
+//uint limit = 0;
+//uint offset = 0;
+
+
+
+//protected $conditionBuilders = [
+//       'NOT' => 'buildNotCondition',
+//       'AND' => 'buildAndCondition',
+//       'OR' => 'buildAndCondition',
+//       'BETWEEN' => 'buildBetweenCondition',
+//       'NOT BETWEEN' => 'buildBetweenCondition',
+//       'IN' => 'buildInCondition',
+//       'NOT IN' => 'buildInCondition',
+//       'LIKE' => 'buildLikeCondition',
+//       'NOT LIKE' => 'buildLikeCondition',
+//       'OR LIKE' => 'buildLikeCondition',
+//       'OR NOT LIKE' => 'buildLikeCondition',
+//       'EXISTS' => 'buildExistsCondition',
+//       'NOT EXISTS' => 'buildExistsCondition',
+//   ];
+
+
 }
 
 #endif // QUERYINTERPRETER_H
