Improved crapview query filters

Removed method 'parseBooleanFilter'
This commit is contained in:
Valentino Orlandi 2024-01-28 17:51:30 +01:00
parent a0f4c9ab57
commit 57decc0d56
Signed by: elB4RTO
GPG Key ID: 1719E976DB2D4E71
2 changed files with 72 additions and 119 deletions

View File

@ -3,6 +3,7 @@
#include "utilities/strings.h"
#include <QRegularExpression>
#include <QStringList>
@ -16,125 +17,73 @@ std::optional<QString> parseNull( const QString& filter_str, const bool to_clean
? filter_str.simplified().toUpper()
: filter_str };
if ( !aux.isEmpty() ) { // here an empty string is considered invalid
if ( aux == "NULL" ) {
result.emplace( "NULL" );
} else if ( aux == "NOT NULL" || aux == "! NULL" || aux == "!NULL" ) {
result.emplace( "NOT NULL" );
if ( aux == "NULL" || aux == "NOT NULL" ) {
result.emplace( QStringLiteral(" IS %1").arg( aux ) );
} else if ( aux == "! NULL" || aux == "!NULL" ) {
result.emplace( QStringLiteral(" IS NOT NULL") );
}
}
return result;
}
std::optional<QString> parseBooleanFilter( const QString& filter_str ) noexcept
{
using opt_t = std::optional<QString>;
opt_t result;
if ( filter_str.isEmpty() ) {
// an empty filter is not invalid
result.emplace("");
return result;
}
QString str{ filter_str.simplified().toUpper() };
// check if the filter is NULL or NOT NULL
if ( opt_t aux=parseNull( str, false ); aux.has_value() ) {
return aux;
}
// normalize the string
if ( str.startsWith("==") ) {
str.remove(0, 2);
} else if ( str.startsWith("=") ) {
str.remove(0, 1);
} else if ( str.startsWith("!=") ) {
str.replace("!=", "NOT ");
} else if ( str.startsWith("!") ) {
str.replace("!", "NOT ");
}
str = str.replace("0", "FALSE").replace("1", "TRUE").simplified();
// apply if valid
if ( str == "TRUE" || str == "NOT FALSE" ) {
result.emplace("= 1");
} else if ( str == "FALSE" || str == "NOT TRUE" ) {
result.emplace("= 0");
}
return result;
}
std::optional<QString> parseNumericFilter( const QString& filter_str ) noexcept
{
using opt_t = std::optional<QString>;
opt_t result;
// a valid string is only composed by a comparison operator followed by a number
static const QRegularExpression expected("^(=|==|!=|<|<=|>=|>)[0-9]+$");
// remove every space from the filter
static const QRegularExpression spaces(R"(\s*)");
if ( filter_str.isEmpty() ) {
// an empty filter is not invalid
result.emplace("");
return result;
return {filter_str};
}
// check if the filter is NULL or NOT NULL
if ( opt_t aux=parseNull( filter_str ); aux.has_value() ) {
if ( const opt_t aux{ parseNull( filter_str ) }; aux.has_value() ) {
return aux;
}
if ( expected.matchView( filter_str ).hasMatch() ) {
return {filter_str};
}
opt_t result;
// normalize the comparison operator
QString aux{ filter_str.simplified() };
if ( aux.startsWith("==") ) {
aux.replace("==", "= ");
} else if ( aux.startsWith("=") ) {
aux.replace("=", "= ");
} else if ( aux.startsWith("!=") ) {
aux.replace("!=", "!= ");
} else if ( aux.startsWith("!") ) {
aux.replace("!", "!= ");
} else if ( aux.startsWith("<=") ) {
aux.replace("<=", "<= ");
} else if ( aux.startsWith("<") ) {
aux.replace("<", "< ");
} else if ( aux.startsWith(">=") ) {
aux.replace(">=", ">= ");
} else if ( aux.startsWith(">") ) {
aux.replace(">", "> ");
} else if ( aux.startsWith("eq ") ) {
aux.replace("eq ", "= ");
} else if ( aux.startsWith("ne ") ) {
aux.replace("ne ", "!= ");
} else if ( aux.startsWith("lt ") ) {
aux.replace("lt ", "< ");
} else if ( aux.startsWith("le ") ) {
aux.replace("le ", "<= ");
} else if ( aux.startsWith("gt ") ) {
aux.replace("gt ", "> ");
} else if ( aux.startsWith("ge ") ) {
aux.replace("ge ", ">= ");
QString aux{ filter_str.toUpper().remove(spaces) };
if ( aux.isEmpty() ) {
return {aux};
} else if ( StringOps::isNumeric( aux ) ) {
aux.prepend( QChar('=') );
} else if ( aux.at(0) == QChar('!') && aux.at(1) != QChar('=') ) {
aux.insert(1, QChar('='));
} else if ( aux.startsWith(QLatin1String("EQ")) ) {
aux.replace(0, 2, QChar('='));
} else if ( aux.startsWith(QLatin1String("NE")) ) {
aux.replace(0, 2, QChar('=')).prepend(QChar('!'));
} else if ( aux.startsWith(QLatin1String("LT")) ) {
aux.replace(0, 2, QChar('<'));
} else if ( aux.startsWith(QLatin1String("LE")) ) {
aux.replace(0, 2, QChar('=')).prepend(QChar('<'));
} else if ( aux.startsWith(QLatin1String("GT")) ) {
aux.replace(0, 2, QChar('>'));
} else if ( aux.startsWith(QLatin1String("GE")) ) {
aux.replace(0, 2, QChar('=')).prepend(QChar('>'));
}
const std::string str{ aux.simplified().toStdString() };
if ( StringOps::isNumeric( str ) ) {
// string is numeric, no need to check further
result.emplace( QString("= %1").arg(str.c_str()) );
return result;
}
// a valid string is only composed by a comparison operator followed by a number
size_t i{ 0ul };
const size_t max{ str.size() };
if ( char c=str.at(i); c == '=' || c == '!' || c == '<' || c == '>' ) {
++i;
if ( i >= max ) {
return result;
}
if ( str.at(i) == '=' ) {
++i;
if ( i >= max ) {
return result;
}
}
if ( str.at(i) == ' ' ) {
++i;
if ( i >= max ) {
return result;
}
}
if ( !StringOps::isNumeric( str.substr(i) ) ) {
return result;
}
result.emplace( QString::fromStdString( str ) );
// final check
if ( expected.matchView( aux ).hasMatch() ) {
result.emplace( aux );
}
return result;
}
@ -143,20 +92,34 @@ std::optional<QString> parseNumericFilter( const QString& filter_str ) noexcept
std::optional<QString> parseTextualFilter( const QString& filter_str ) noexcept
{
using opt_t =std::optional<QString>;
opt_t result;
if ( filter_str.isEmpty() ) {
// an empty filter is not invalid
result.emplace("");
return result;
return {filter_str};
}
// check if the filter is NULL or NOT NULL
if ( opt_t aux=parseNull( filter_str ); aux.has_value() ) {
if ( const opt_t aux{ parseNull( filter_str ) }; aux.has_value() ) {
return aux;
}
if ( filter_str == "*" ) {
result.emplace("NOT NULL");
opt_t result;
QString aux{ filter_str.trimmed() };
if ( aux.isEmpty() ) {
return {aux};
} else if ( aux == "*" ) {
result.emplace(QStringLiteral(" IS NOT NULL"));
} else {
result.emplace( filter_str.trimmed() );
if ( aux.startsWith(QChar('!')) ) {
result.emplace( QStringLiteral(" NOT LIKE '%1'").arg( aux.removeFirst().trimmed().replace(QChar('\''),QLatin1String("''")) ) );
} else {
if ( aux.startsWith(QChar('\\')) ) {
aux.removeFirst();
}
result.emplace( QStringLiteral(" LIKE '%1'").arg( aux.replace(QChar('\''),QLatin1String("''")) ) );
}
}
return result;
}

View File

@ -25,16 +25,6 @@ namespace FilterOps
*/
std::optional<QString> parseNull( const QString& filter_str, const bool to_clean=true ) noexcept;
//! Parses a filter for a database field with boolean type
/*!
Boolean filters are not locale-dependant,
meaning that English syntax must be used: 'TRUE', 'FALSE'.
This filter is case-insensitive.
\param field_str The given filter
\return The resulting filter to apply to the query, if valid
*/
std::optional<QString> parseBooleanFilter( const QString& filter_str ) noexcept;
//! Parses a filter for a log field with integer type
/*!
The filter can be composed by anumber or by a comparison operator followed by a number.