1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
|
#ifndef STATEMENTTOKENBUILDER_H
#define STATEMENTTOKENBUILDER_H
#include "token.h"
#include "ast/sqliteconflictalgo.h"
#include "ast/sqlitesortorder.h"
class SqliteStatement;
/**
* @brief Builder producing token list basing on certain inputs.
*
* This builder provides several methods to build list of tokens from various input values. It can produce
* token list for entire AST objects, or it can produce token list for list of names, etc.
*
* Token builder is used in SqliteStatement derived classes to rebuild SqliteStatement::tokens basing on the
* values in their class members.
*
* Typical use case:
* @code
* TokenList SqliteCreateView::rebuildTokensFromContents()
* {
* StatementTokenBuilder builder;
*
* builder.withKeyword("CREATE").withSpace();
* if (tempKw)
* builder.withKeyword("TEMP").withSpace();
* else if (temporaryKw)
* builder.withKeyword("TEMPORARY").withSpace();
*
* builder.withKeyword("VIEW").withSpace();
* if (ifNotExists)
* builder.withKeyword("IF").withSpace().withKeyword("NOT").withSpace().withKeyword("EXISTS").withSpace();
*
* if (!database.isNull())
* builder.withOther(database).withOperator(".");
*
* builder.withOther(view).withSpace().withKeyword("AS").withStatement(select);
*
* return builder.build();
* }
* @endcode
*/
class StatementTokenBuilder
{
public:
/**
* @brief Adds keyword token.
* @param value Value of the keyword token.
* @return Reference to the builder for the further building.
*
* Keyword \p value gets converted to upper case.
*/
StatementTokenBuilder& withKeyword(const QString& value);
/**
* @brief Adds "other" token (some object name, or other word).
* @param value Value for the token.
* @return Reference to the builder for the further building.
*
* This is used for table names, etc. The \p value is quoted just as passed.
*/
StatementTokenBuilder& withOther(const QString& value);
/**
* @brief Adds "other" token (some object name, or other word).
* @param value Value for the token.
* @param wrapIfNeeded Defined whether the value should be wrapped if identified to require wrapping (i.e. is a keyword, or multiword).
* @return Reference to the builder for the further building.
*
* This is used for table names, etc. The \p value is quoted just as passed.
* You may want to pass wrapIfNeeded=false if you know that this may be equal to keyword,
* that is allowed as ID too (Lemon's fallback to ID).
*/
StatementTokenBuilder& withOther(const QString& value, bool wrapIfNeeded);
/**
* @brief Adds string using double-quote wrapping.
* @param value Value for the token.
* @return Reference to the builder for the further building.
*
* The \p value is wrapped with double quote, but if it's not possible then the proper wrapper is used by wrapObjIfNeeded().
*
* @overload
*/
StatementTokenBuilder& withStringPossiblyOther(const QString& value);
/**
* @brief Adds list of "other" tokens.
* @param value List of values for tokens.
* @param separator Optional value for separator tokens.
* @return Reference to the builder for the further building.
*
* Given the input \p value, this method produces list of tokens. Additionally it can put extra separator
* token between all produced tokens using the \p separator value. To skip separator tokens pass
* an empty string as the separator value.
*/
StatementTokenBuilder& withOtherList(const QList<QString>& value, const QString& separator = ",");
/**
* @brief Adds operator token.
* @param value Value of the operator (";", "+", etc).
* @return Reference to the builder for the further building.
*/
StatementTokenBuilder& withOperator(const QString& value);
/**
* @brief Adds comment token.
* @param value Comment value, including start/end characters of the comment.
* @return Reference to the builder for the further building.
*/
StatementTokenBuilder& withComment(const QString& value);
/**
* @brief Adds decimal number token.
* @param value Value for the token.
* @return Reference to the builder for the further building.
*/
StatementTokenBuilder& withFloat(const QVariant &value);
/**
* @brief Add integer numer token.
* @param value Value for the token.
* @return Reference to the builder for the further building.
*/
StatementTokenBuilder& withInteger(qint64 value);
/**
* @brief Adds bind parameter token.
* @param value Name of the bind parameter, including ":" or "@" at the begining.
* @return Reference to the builder for the further building.
*/
StatementTokenBuilder& withBindParam(const QString& value);
/**
* @brief Adds left parenthesis token (<tt>"("</tt>).
* @return Reference to the builder for the further building.
*/
StatementTokenBuilder& withParLeft();
/**
* @brief Adds right parenthesis token (<tt>")"</tt>).
* @return Reference to the builder for the further building.
*/
StatementTokenBuilder& withParRight();
/**
* @brief Adds a single whitespace token.
* @return Reference to the builder for the further building.
*/
StatementTokenBuilder& withSpace();
/**
* @brief Adds BLOB value token.
* @param value BLOB value for the token.
* @return Reference to the builder for the further building.
*/
StatementTokenBuilder& withBlob(const QString& value);
/**
* @brief Adds string value token.
* @param value Value for the token.
* @return Reference to the builder for the further building.
*
* The string is wrapped with single quote characters if it's not wrapped yet.
*/
StatementTokenBuilder& withString(const QString& value);
/**
* @brief Adds set of tokens represeting "ON CONFLICT" statement.
* @param onConflict Conflict resolution algorithm to build for.
* @return Reference to the builder for the further building.
*
* If algorithm is SqliteConflictAlgo::null, no tokens are added.
*/
StatementTokenBuilder& withConflict(SqliteConflictAlgo onConflict);
/**
* @brief Adds space and <tt>"ASC"/"DESC"</tt> token.
* @param sortOrder Sort order to use.
* @return Reference to the builder for the further building.
*
* If the sort order is SqliteSortOrder::null, no tokens are added.
*/
StatementTokenBuilder& withSortOrder(SqliteSortOrder sortOrder);
/**
* @brief Adds set of tokens representing entire statement.
* @param stmt Statement to add tokens for.
* @return Reference to the builder for the further building.
*/
StatementTokenBuilder& withStatement(SqliteStatement* stmt);
/**
* @brief Adds already defined list of tokens to this builder.
* @param tokens Tokens to add.
* @return Reference to the builder for the further building.
*/
StatementTokenBuilder& withTokens(TokenList tokens);
/**
* @brief Adds literal value token (integer, decimal, string, BLOB).
* @param value Value for the token.
* @return Reference to the builder for the further building.
*
* This method tries to convert given \p value to integer,
* then to double, then it checks if the value has format <tt>X'...'</tt>
* and if if succeeded at any of those steps, then it adds appropriate
* token. If none of above succeeded, then the string token is added.
*/
StatementTokenBuilder& withLiteralValue(const QVariant& value);
/**
* @brief Adds tokens representing list of entire statements.
* @param stmtList List of statements to add tokens for.
* @param separator Optional separator to be used for separator tokens.
* @return Reference to the builder for the further building.
*
* This method is very similar to withOtherList(), except it works
* on the entire statements.
*/
template <class T>
StatementTokenBuilder& withStatementList(QList<T*> stmtList, const QString& separator = ",")
{
bool first = true;
for (T* stmt : stmtList)
{
if (!first)
{
if (!separator.isEmpty())
withOperator(separator);
withSpace();
}
withStatement(stmt);
first = false;
}
return *this;
}
/**
* @brief Provides all tokens added so far as a compat token list.
* @return List of tokens built so far.
*/
TokenList build() const;
/**
* @brief Cleans up all tokens added so far.
*/
void clear();
private:
/**
* @brief Adds token of given type and value.
* @param type Type of the token to add.
* @param value Value for the token to add.
* @return Reference to the builder for the further building.
*/
StatementTokenBuilder& with(Token::Type type, const QString& value);
/**
* @brief List of tokens added so far.
*/
TokenList tokens;
/**
* @brief Current character position index.
*
* This index is used to generate proper values for Token::start and Token::end.
* Each added token increments this index by the value length.
*/
int currentIdx = 0;
};
#endif // STATEMENTTOKENBUILDER_H
|