Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 3160499c

Von Christian Ehringfeld vor mehr als 8 Jahren hinzugefügt

  • ID 3160499ccda0138accf32cef2b9478b2a7dc6bd3
  • Vorgänger b9dcff08
  • Nachfolger 38838b5b

queryinterpreter/builder wip

Unterschiede anzeigen:

EntityManager.pro
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 \
......
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
src/expression.cpp
#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;
}
src/expression.h
#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
src/join.cpp
}
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;
......
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;
}
src/join.h
#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;
......
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;
};
}
src/orderby.cpp
#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;
}
src/orderby.h
#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
src/query.cpp
#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;
}
......
void Query::setSelectOption(const QString &value) {
selectOption = value;
}
bool Query::getDistinct() const {
return distinct;
}
......
void Query::setDistinct(bool value) {
distinct = value;
}
QStringList Query::getFrom() const {
return from;
}
......
void Query::setFrom(const QStringList &value) {
from = value;
}
QStringList Query::getGroupBy() const {
return groupBy;
}
......
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;
}
......
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;
}
src/query.h
#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);
......
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);
......
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;
src/querybuilder.cpp
QSharedPointer<Database> database) {
this->schema = schema;
this->database = database;
this->separator = " ";
}
QueryBuilder::~QueryBuilder() {
......
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));
......
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,
......
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);
}
......
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());
}
......
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,
......
query.appendParam(i.key(), i.value());
}
condition += ")";
query.appendCondition(condition);
query.appendWhereCondition(condition);
}
}
src/querybuilder.h
* 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();
......
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:
......
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;
......
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;
};
src/queryinterpreter.cpp
#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;
......
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 "";
}
src/queryinterpreter.h
#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

Auch abrufbar als: Unified diff