mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 09:56:38 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			185 lines
		
	
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			185 lines
		
	
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "query.hpp"
 | |
| 
 | |
| #include <sstream>
 | |
| #include <iomanip>
 | |
| 
 | |
| namespace Queries
 | |
| {
 | |
|     Field::Field(std::vector<std::string> path, std::type_index type)
 | |
|         : mPath(std::move(path))
 | |
|         , mType(type) {}
 | |
| 
 | |
|     std::string Field::toString() const
 | |
|     {
 | |
|         std::string result;
 | |
|         for (const std::string& segment : mPath)
 | |
|         {
 | |
|             if (!result.empty())
 | |
|                 result += ".";
 | |
|             result += segment;
 | |
|         }
 | |
|         return result;
 | |
|     }
 | |
| 
 | |
|     std::string toString(const FieldValue& value)
 | |
|     {
 | |
|         return std::visit([](auto&& arg) -> std::string
 | |
|         {
 | |
|             using T = std::decay_t<decltype(arg)>;
 | |
|             if constexpr (std::is_same_v<T, std::string>)
 | |
|             {
 | |
|                 std::ostringstream oss;
 | |
|                 oss << std::quoted(arg);
 | |
|                 return oss.str();
 | |
|             }
 | |
|             else if constexpr (std::is_same_v<T, bool>)
 | |
|                 return arg ? "true" : "false";
 | |
|             else
 | |
|                 return std::to_string(arg);
 | |
|         }, value);
 | |
|     }
 | |
| 
 | |
|     std::string Condition::toString() const
 | |
|     {
 | |
|         std::string res;
 | |
|         res += mField->toString();
 | |
|         switch (mType)
 | |
|         {
 | |
|             case Condition::EQUAL: res += " == "; break;
 | |
|             case Condition::NOT_EQUAL: res += " != "; break;
 | |
|             case Condition::LESSER: res += " < "; break;
 | |
|             case Condition::LESSER_OR_EQUAL: res += " <= "; break;
 | |
|             case Condition::GREATER: res += " > "; break;
 | |
|             case Condition::GREATER_OR_EQUAL: res += " >= "; break;
 | |
|             case Condition::LIKE: res += " LIKE "; break;
 | |
|         }
 | |
|         res += Queries::toString(mValue);
 | |
|         return res;
 | |
|     }
 | |
| 
 | |
|     void Filter::add(const Condition& c, Operation::Type op)
 | |
|     {
 | |
|         mOperations.push_back({Operation::PUSH, mConditions.size()});
 | |
|         mConditions.push_back(c);
 | |
|         if (mConditions.size() > 1)
 | |
|             mOperations.push_back({op, 0});
 | |
|     }
 | |
| 
 | |
|     void Filter::add(const Filter& f, Operation::Type op)
 | |
|     {
 | |
|         size_t conditionOffset = mConditions.size();
 | |
|         size_t operationsBefore = mOperations.size();
 | |
|         mConditions.insert(mConditions.end(), f.mConditions.begin(), f.mConditions.end());
 | |
|         mOperations.insert(mOperations.end(), f.mOperations.begin(), f.mOperations.end());
 | |
|         for (size_t i = operationsBefore; i < mOperations.size(); ++i)
 | |
|             mOperations[i].mConditionIndex += conditionOffset;
 | |
|         if (conditionOffset > 0 && !f.mConditions.empty())
 | |
|             mOperations.push_back({op, 0});
 | |
|     }
 | |
| 
 | |
|     std::string Filter::toString() const
 | |
|     {
 | |
|         if(mOperations.empty())
 | |
|             return "";
 | |
|         std::vector<std::string> stack;
 | |
|         auto pop = [&stack](){ auto v = stack.back(); stack.pop_back(); return v; };
 | |
|         auto push = [&stack](const std::string& s) { stack.push_back(s); };
 | |
|         for (const Operation& op : mOperations)
 | |
|         {
 | |
|             if(op.mType == Operation::PUSH)
 | |
|                 push(mConditions[op.mConditionIndex].toString());
 | |
|             else if(op.mType == Operation::AND)
 | |
|             {
 | |
|                 auto rhs = pop();
 | |
|                 auto lhs = pop();
 | |
|                 std::string res;
 | |
|                 res += "(";
 | |
|                 res += lhs;
 | |
|                 res += ") AND (";
 | |
|                 res += rhs;
 | |
|                 res += ")";
 | |
|                 push(res);
 | |
|             }
 | |
|             else if (op.mType == Operation::OR)
 | |
|             {
 | |
|                 auto rhs = pop();
 | |
|                 auto lhs = pop();
 | |
|                 std::string res;
 | |
|                 res += "(";
 | |
|                 res += lhs;
 | |
|                 res += ") OR (";
 | |
|                 res += rhs;
 | |
|                 res += ")";
 | |
|                 push(res);
 | |
|             }
 | |
|             else if (op.mType == Operation::NOT)
 | |
|             {
 | |
|                 std::string res;
 | |
|                 res += "NOT (";
 | |
|                 res += pop();
 | |
|                 res += ")";
 | |
|                 push(res);
 | |
|             }
 | |
|             else
 | |
|                 throw std::logic_error("Unknown operation type!");
 | |
|         }
 | |
|         return pop();
 | |
|     }
 | |
| 
 | |
|     std::string Query::toString() const
 | |
|     {
 | |
|         std::string res;
 | |
|         res += "SELECT ";
 | |
|         res += mQueryType;
 | |
| 
 | |
|         std::string filter = mFilter.toString();
 | |
|         if(!filter.empty())
 | |
|         {
 | |
|             res += " WHERE ";
 | |
|             res += filter;
 | |
|         }
 | |
| 
 | |
|         std::string order;
 | |
|         for(const OrderBy& ord : mOrderBy)
 | |
|         {
 | |
|             if(!order.empty())
 | |
|                 order += ", ";
 | |
|             order += ord.mField->toString();
 | |
|             if(ord.mDescending)
 | |
|                 order += " DESC";
 | |
|         }
 | |
|         if (!order.empty())
 | |
|         {
 | |
|             res += " ORDER BY ";
 | |
|             res += order;
 | |
|         }
 | |
| 
 | |
|         std::string group;
 | |
|         for (const Field* f: mGroupBy)
 | |
|         {
 | |
|             if (!group.empty())
 | |
|                 group += " ,";
 | |
|             group += f->toString();
 | |
|         }
 | |
|         if (!group.empty())
 | |
|         {
 | |
|             res += " GROUP BY ";
 | |
|             res += group;
 | |
|         }
 | |
| 
 | |
|         if (mLimit != sNoLimit)
 | |
|         {
 | |
|             res += " LIMIT ";
 | |
|             res += std::to_string(mLimit);
 | |
|         }
 | |
| 
 | |
|         if (mOffset != 0)
 | |
|         {
 | |
|             res += " OFFSET ";
 | |
|             res += std::to_string(mOffset);
 | |
|         }
 | |
| 
 | |
|         return res;
 | |
|     }
 | |
| }
 | |
| 
 |