diff --git a/cli/cli.pro b/cli/cli.pro index 1c124f6..9466cb9 100644 --- a/cli/cli.pro +++ b/cli/cli.pro @@ -1,6 +1,6 @@ QT -= gui QT += sql concurrent -CONFIG += c++11 console +CONFIG += c++17 console CONFIG -= app_bundle # The following define makes your compiler emit warnings if you use @@ -32,7 +32,8 @@ SOURCES += \ databasefactory.cpp \ sqlitedbservice.cpp \ logger.cpp \ - commandsearch.cpp + commandsearch.cpp \ + commandlist.cpp HEADERS += \ encodingdetector.h \ @@ -53,7 +54,8 @@ HEADERS += \ databasefactory.h \ sqlitedbservice.h \ logger.h \ - commandsearch.h + commandsearch.h \ + commandlist.h INCLUDEPATH += /usr/include/poppler/qt5/ /usr/include/quazip5 diff --git a/cli/commandsearch.cpp b/cli/commandsearch.cpp index f913dc7..4765b93 100644 --- a/cli/commandsearch.cpp +++ b/cli/commandsearch.cpp @@ -25,8 +25,7 @@ int CommandSearch::handle(QStringList arguments) QStringList files = parser.positionalArguments(); QString queryStrings = files.join(' '); - - auto results = dbService->search(queryStrings); + auto results = dbService->search(QSSQuery::build(queryStrings)); for(SearchResult &result : results) { diff --git a/cli/sqlitedbservice.cpp b/cli/sqlitedbservice.cpp index 691483e..5cc0fe5 100644 --- a/cli/sqlitedbservice.cpp +++ b/cli/sqlitedbservice.cpp @@ -21,11 +21,11 @@ bool SqliteDbService::fileExistsInDatabase(QString path, qint64 mtime) return query.value(0).toBool(); } -QVector SqliteDbService::search(QString searchQuery) +QVector SqliteDbService::search(const QSSQuery &query) { auto connection = dbFactory->forCurrentThread(); SqliteSearch searcher(connection); - return searcher.search(searchQuery); + return searcher.search(query); } bool SqliteDbService::fileExistsInDatabase(QString path) diff --git a/cli/sqlitedbservice.h b/cli/sqlitedbservice.h index 6ead073..d80857a 100644 --- a/cli/sqlitedbservice.h +++ b/cli/sqlitedbservice.h @@ -6,6 +6,7 @@ #include "pagedata.h" #include "filedata.h" #include "../shared/sqlitesearch.h" +#include "../shared/token.h" enum SaveFileResult { OK, @@ -26,7 +27,7 @@ class SqliteDbService bool deleteFile(QString path); bool fileExistsInDatabase(QString path); bool fileExistsInDatabase(QString path, qint64 mtime); - QVector search(QString searchQuery); + QVector search(const QSSQuery &query); }; #endif // SQLITEDBSERVICE_H diff --git a/gui/gui.pro b/gui/gui.pro index 3ce5ab5..afe47d7 100644 --- a/gui/gui.pro +++ b/gui/gui.pro @@ -7,7 +7,7 @@ QT += core concurrent gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets -CONFIG += c++14 +CONFIG += c++17 TARGET = qss-gui TEMPLATE = app diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index a82cd4a..923fe47 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -16,6 +16,7 @@ #include "clicklabel.h" #include "../shared/sqlitesearch.h" #include "../shared/qssgeneralexception.h" +#include "../shared/qssquery.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); @@ -150,7 +151,7 @@ void MainWindow::pdfPreviewReceived(PdfPreview preview) void MainWindow::lineEditReturnPressed() { QString q = ui->txtSearch->text(); - if(!SqliteSearch::checkParanthesis(q)) + if(!QSSQuery::checkParanthesis(q)) { ui->lblSearchResults->setText("Invalid paranthesis"); return; @@ -163,7 +164,7 @@ void MainWindow::lineEditReturnPressed() [&, q]() { SqliteSearch searcher(db); - return searcher.search(q); + return searcher.search(QSSQuery::build(q)); }); searchWatcher.setFuture(searchFuture); } diff --git a/gui/moc_predefs.h b/gui/moc_predefs.h deleted file mode 100644 index c692089..0000000 --- a/gui/moc_predefs.h +++ /dev/null @@ -1,389 +0,0 @@ -#define __SSP_STRONG__ 3 -#define __DBL_MIN_EXP__ (-1021) -#define __FLT32X_MAX_EXP__ 1024 -#define __cpp_attributes 200809 -#define __UINT_LEAST16_MAX__ 0xffff -#define __ATOMIC_ACQUIRE 2 -#define __FLT128_MAX_10_EXP__ 4932 -#define __FLT_MIN__ 1.17549435082228750796873653722224568e-38F -#define __GCC_IEC_559_COMPLEX 2 -#define __cpp_aggregate_nsdmi 201304 -#define __UINT_LEAST8_TYPE__ unsigned char -#define __SIZEOF_FLOAT80__ 16 -#define __INTMAX_C(c) c##L -#define __CHAR_BIT__ 8 -#define __UINT8_MAX__ 0xff -#define __WINT_MAX__ 0xffffffffU -#define __FLT32_MIN_EXP__ (-125) -#define __cpp_static_assert 200410 -#define __ORDER_LITTLE_ENDIAN__ 1234 -#define __SIZE_MAX__ 0xffffffffffffffffUL -#define __WCHAR_MAX__ 0x7fffffff -#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1 -#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1 -#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1 -#define __DBL_DENORM_MIN__ double(4.94065645841246544176568792868221372e-324L) -#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1 -#define __GCC_ATOMIC_CHAR_LOCK_FREE 2 -#define __GCC_IEC_559 2 -#define __FLT32X_DECIMAL_DIG__ 17 -#define __FLT_EVAL_METHOD__ 0 -#define __unix__ 1 -#define __cpp_binary_literals 201304 -#define __FLT64_DECIMAL_DIG__ 17 -#define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 2 -#define __x86_64 1 -#define __cpp_variadic_templates 200704 -#define __UINT_FAST64_MAX__ 0xffffffffffffffffUL -#define __SIG_ATOMIC_TYPE__ int -#define __DBL_MIN_10_EXP__ (-307) -#define __FINITE_MATH_ONLY__ 0 -#define __cpp_variable_templates 201304 -#define __GNUC_PATCHLEVEL__ 0 -#define __FLT32_HAS_DENORM__ 1 -#define __UINT_FAST8_MAX__ 0xff -#define __has_include(STR) __has_include__(STR) -#define __DEC64_MAX_EXP__ 385 -#define __INT8_C(c) c -#define __INT_LEAST8_WIDTH__ 8 -#define __UINT_LEAST64_MAX__ 0xffffffffffffffffUL -#define __SHRT_MAX__ 0x7fff -#define __LDBL_MAX__ 1.18973149535723176502126385303097021e+4932L -#define __FLT64X_MAX_10_EXP__ 4932 -#define __UINT_LEAST8_MAX__ 0xff -#define __GCC_ATOMIC_BOOL_LOCK_FREE 2 -#define __FLT128_DENORM_MIN__ 6.47517511943802511092443895822764655e-4966F128 -#define __UINTMAX_TYPE__ long unsigned int -#define __linux 1 -#define __DEC32_EPSILON__ 1E-6DF -#define __FLT_EVAL_METHOD_TS_18661_3__ 0 -#define __unix 1 -#define __UINT32_MAX__ 0xffffffffU -#define __GXX_EXPERIMENTAL_CXX0X__ 1 -#define __LDBL_MAX_EXP__ 16384 -#define __FLT128_MIN_EXP__ (-16381) -#define __WINT_MIN__ 0U -#define __linux__ 1 -#define __FLT128_MIN_10_EXP__ (-4931) -#define __INT_LEAST16_WIDTH__ 16 -#define __SCHAR_MAX__ 0x7f -#define __FLT128_MANT_DIG__ 113 -#define __WCHAR_MIN__ (-__WCHAR_MAX__ - 1) -#define __INT64_C(c) c##L -#define __DBL_DIG__ 15 -#define __GCC_ATOMIC_POINTER_LOCK_FREE 2 -#define __FLT64X_MANT_DIG__ 64 -#define _FORTIFY_SOURCE ((defined __OPTIMIZE__ && __OPTIMIZE__ > 0) ? 2 : 0) -#define __SIZEOF_INT__ 4 -#define __SIZEOF_POINTER__ 8 -#define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 2 -#define __USER_LABEL_PREFIX__ -#define __FLT64X_EPSILON__ 1.08420217248550443400745280086994171e-19F64x -#define __STDC_HOSTED__ 1 -#define __LDBL_HAS_INFINITY__ 1 -#define __FLT32_DIG__ 6 -#define __FLT_EPSILON__ 1.19209289550781250000000000000000000e-7F -#define __GXX_WEAK__ 1 -#define __SHRT_WIDTH__ 16 -#define __LDBL_MIN__ 3.36210314311209350626267781732175260e-4932L -#define __DEC32_MAX__ 9.999999E96DF -#define __cpp_threadsafe_static_init 200806 -#define __FLT64X_DENORM_MIN__ 3.64519953188247460252840593361941982e-4951F64x -#define __FLT32X_HAS_INFINITY__ 1 -#define __INT32_MAX__ 0x7fffffff -#define __INT_WIDTH__ 32 -#define __SIZEOF_LONG__ 8 -#define __STDC_IEC_559__ 1 -#define __STDC_ISO_10646__ 201706L -#define __UINT16_C(c) c -#define __PTRDIFF_WIDTH__ 64 -#define __DECIMAL_DIG__ 21 -#define __FLT64_EPSILON__ 2.22044604925031308084726333618164062e-16F64 -#define __gnu_linux__ 1 -#define __INTMAX_WIDTH__ 64 -#define __FLT64_MIN_EXP__ (-1021) -#define __has_include_next(STR) __has_include_next__(STR) -#define __FLT64X_MIN_10_EXP__ (-4931) -#define __LDBL_HAS_QUIET_NAN__ 1 -#define __FLT64_MANT_DIG__ 53 -#define __GNUC__ 8 -#define __GXX_RTTI 1 -#define __pie__ 2 -#define __MMX__ 1 -#define __cpp_delegating_constructors 200604 -#define __FLT_HAS_DENORM__ 1 -#define __SIZEOF_LONG_DOUBLE__ 16 -#define __BIGGEST_ALIGNMENT__ 16 -#define __STDC_UTF_16__ 1 -#define __FLT64_MAX_10_EXP__ 308 -#define __FLT32_HAS_INFINITY__ 1 -#define __DBL_MAX__ double(1.79769313486231570814527423731704357e+308L) -#define __cpp_raw_strings 200710 -#define __INT_FAST32_MAX__ 0x7fffffffffffffffL -#define __DBL_HAS_INFINITY__ 1 -#define __DEC32_MIN_EXP__ (-94) -#define __INTPTR_WIDTH__ 64 -#define __FLT32X_HAS_DENORM__ 1 -#define __INT_FAST16_TYPE__ long int -#define __LDBL_HAS_DENORM__ 1 -#define __cplusplus 201402L -#define __cpp_ref_qualifiers 200710 -#define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL -#define __INT_LEAST32_MAX__ 0x7fffffff -#define __DEC32_MIN__ 1E-95DF -#define __DEPRECATED 1 -#define __cpp_rvalue_references 200610 -#define __DBL_MAX_EXP__ 1024 -#define __WCHAR_WIDTH__ 32 -#define __FLT32_MAX__ 3.40282346638528859811704183484516925e+38F32 -#define __DEC128_EPSILON__ 1E-33DL -#define __SSE2_MATH__ 1 -#define __ATOMIC_HLE_RELEASE 131072 -#define __PTRDIFF_MAX__ 0x7fffffffffffffffL -#define __amd64 1 -#define __ATOMIC_HLE_ACQUIRE 65536 -#define __FLT32_HAS_QUIET_NAN__ 1 -#define __GNUG__ 8 -#define __LONG_LONG_MAX__ 0x7fffffffffffffffLL -#define __SIZEOF_SIZE_T__ 8 -#define __cpp_rvalue_reference 200610 -#define __cpp_nsdmi 200809 -#define __FLT64X_MIN_EXP__ (-16381) -#define __SIZEOF_WINT_T__ 4 -#define __LONG_LONG_WIDTH__ 64 -#define __cpp_initializer_lists 200806 -#define __FLT32_MAX_EXP__ 128 -#define __cpp_hex_float 201603 -#define __GCC_HAVE_DWARF2_CFI_ASM 1 -#define __GXX_ABI_VERSION 1013 -#define __FLT128_HAS_INFINITY__ 1 -#define __FLT_MIN_EXP__ (-125) -#define __cpp_lambdas 200907 -#define __FLT64X_HAS_QUIET_NAN__ 1 -#define __INT_FAST64_TYPE__ long int -#define __FLT64_DENORM_MIN__ 4.94065645841246544176568792868221372e-324F64 -#define __DBL_MIN__ double(2.22507385850720138309023271733240406e-308L) -#define __PIE__ 2 -#define __LP64__ 1 -#define __FLT32X_EPSILON__ 2.22044604925031308084726333618164062e-16F32x -#define __DECIMAL_BID_FORMAT__ 1 -#define __FLT64_MIN_10_EXP__ (-307) -#define __FLT64X_DECIMAL_DIG__ 21 -#define __DEC128_MIN__ 1E-6143DL -#define __REGISTER_PREFIX__ -#define __UINT16_MAX__ 0xffff -#define __DBL_HAS_DENORM__ 1 -#define __FLT32_MIN__ 1.17549435082228750796873653722224568e-38F32 -#define __UINT8_TYPE__ unsigned char -#define __NO_INLINE__ 1 -#define __FLT_MANT_DIG__ 24 -#define __LDBL_DECIMAL_DIG__ 21 -#define __VERSION__ "8.2.0" -#define __UINT64_C(c) c##UL -#define __cpp_unicode_characters 200704 -#define _STDC_PREDEF_H 1 -#define __cpp_decltype_auto 201304 -#define __GCC_ATOMIC_INT_LOCK_FREE 2 -#define __FLT128_MAX_EXP__ 16384 -#define __FLT32_MANT_DIG__ 24 -#define __FLOAT_WORD_ORDER__ __ORDER_LITTLE_ENDIAN__ -#define __STDC_IEC_559_COMPLEX__ 1 -#define __FLT128_HAS_DENORM__ 1 -#define __FLT128_DIG__ 33 -#define __SCHAR_WIDTH__ 8 -#define __INT32_C(c) c -#define __DEC64_EPSILON__ 1E-15DD -#define __ORDER_PDP_ENDIAN__ 3412 -#define __DEC128_MIN_EXP__ (-6142) -#define __FLT32_MAX_10_EXP__ 38 -#define __INT_FAST32_TYPE__ long int -#define __UINT_LEAST16_TYPE__ short unsigned int -#define __FLT64X_HAS_INFINITY__ 1 -#define unix 1 -#define __INT16_MAX__ 0x7fff -#define __cpp_rtti 199711 -#define __SIZE_TYPE__ long unsigned int -#define __UINT64_MAX__ 0xffffffffffffffffUL -#define __FLT64X_DIG__ 18 -#define __INT8_TYPE__ signed char -#define __cpp_digit_separators 201309 -#define __ELF__ 1 -#define __GCC_ASM_FLAG_OUTPUTS__ 1 -#define __FLT_RADIX__ 2 -#define __INT_LEAST16_TYPE__ short int -#define __LDBL_EPSILON__ 1.08420217248550443400745280086994171e-19L -#define __UINTMAX_C(c) c##UL -#define __GLIBCXX_BITSIZE_INT_N_0 128 -#define __k8 1 -#define __SIG_ATOMIC_MAX__ 0x7fffffff -#define __GCC_ATOMIC_WCHAR_T_LOCK_FREE 2 -#define __SIZEOF_PTRDIFF_T__ 8 -#define __FLT32X_MANT_DIG__ 53 -#define __x86_64__ 1 -#define __FLT32X_MIN_EXP__ (-1021) -#define __DEC32_SUBNORMAL_MIN__ 0.000001E-95DF -#define __INT_FAST16_MAX__ 0x7fffffffffffffffL -#define __FLT64_DIG__ 15 -#define __UINT_FAST32_MAX__ 0xffffffffffffffffUL -#define __UINT_LEAST64_TYPE__ long unsigned int -#define __FLT_HAS_QUIET_NAN__ 1 -#define __FLT_MAX_10_EXP__ 38 -#define __LONG_MAX__ 0x7fffffffffffffffL -#define __FLT64X_HAS_DENORM__ 1 -#define __DEC128_SUBNORMAL_MIN__ 0.000000000000000000000000000000001E-6143DL -#define __FLT_HAS_INFINITY__ 1 -#define __cpp_unicode_literals 200710 -#define __UINT_FAST16_TYPE__ long unsigned int -#define __DEC64_MAX__ 9.999999999999999E384DD -#define __INT_FAST32_WIDTH__ 64 -#define __CHAR16_TYPE__ short unsigned int -#define __PRAGMA_REDEFINE_EXTNAME 1 -#define __SIZE_WIDTH__ 64 -#define __SEG_FS 1 -#define __INT_LEAST16_MAX__ 0x7fff -#define __DEC64_MANT_DIG__ 16 -#define __INT64_MAX__ 0x7fffffffffffffffL -#define __UINT_LEAST32_MAX__ 0xffffffffU -#define __SEG_GS 1 -#define __FLT32_DENORM_MIN__ 1.40129846432481707092372958328991613e-45F32 -#define __GCC_ATOMIC_LONG_LOCK_FREE 2 -#define __SIG_ATOMIC_WIDTH__ 32 -#define __INT_LEAST64_TYPE__ long int -#define __INT16_TYPE__ short int -#define __INT_LEAST8_TYPE__ signed char -#define __DEC32_MAX_EXP__ 97 -#define __INT_FAST8_MAX__ 0x7f -#define __FLT128_MAX__ 1.18973149535723176508575932662800702e+4932F128 -#define __INTPTR_MAX__ 0x7fffffffffffffffL -#define __cpp_sized_deallocation 201309 -#define linux 1 -#define __cpp_range_based_for 200907 -#define __FLT64_HAS_QUIET_NAN__ 1 -#define __FLT32_MIN_10_EXP__ (-37) -#define __SSE2__ 1 -#define __EXCEPTIONS 1 -#define __LDBL_MANT_DIG__ 64 -#define __DBL_HAS_QUIET_NAN__ 1 -#define __FLT64_HAS_INFINITY__ 1 -#define __FLT64X_MAX__ 1.18973149535723176502126385303097021e+4932F64x -#define __SIG_ATOMIC_MIN__ (-__SIG_ATOMIC_MAX__ - 1) -#define __code_model_small__ 1 -#define __cpp_return_type_deduction 201304 -#define __k8__ 1 -#define __INTPTR_TYPE__ long int -#define __UINT16_TYPE__ short unsigned int -#define __WCHAR_TYPE__ int -#define __SIZEOF_FLOAT__ 4 -#define __pic__ 2 -#define __UINTPTR_MAX__ 0xffffffffffffffffUL -#define __INT_FAST64_WIDTH__ 64 -#define __DEC64_MIN_EXP__ (-382) -#define __cpp_decltype 200707 -#define __FLT32_DECIMAL_DIG__ 9 -#define __INT_FAST64_MAX__ 0x7fffffffffffffffL -#define __GCC_ATOMIC_TEST_AND_SET_TRUEVAL 1 -#define __FLT_DIG__ 6 -#define __FLT64X_MAX_EXP__ 16384 -#define __UINT_FAST64_TYPE__ long unsigned int -#define __INT_MAX__ 0x7fffffff -#define __amd64__ 1 -#define __INT64_TYPE__ long int -#define __FLT_MAX_EXP__ 128 -#define __ORDER_BIG_ENDIAN__ 4321 -#define __DBL_MANT_DIG__ 53 -#define __cpp_inheriting_constructors 201511 -#define __SIZEOF_FLOAT128__ 16 -#define __INT_LEAST64_MAX__ 0x7fffffffffffffffL -#define __DEC64_MIN__ 1E-383DD -#define __WINT_TYPE__ unsigned int -#define __UINT_LEAST32_TYPE__ unsigned int -#define __SIZEOF_SHORT__ 2 -#define __SSE__ 1 -#define __LDBL_MIN_EXP__ (-16381) -#define __FLT64_MAX__ 1.79769313486231570814527423731704357e+308F64 -#define __WINT_WIDTH__ 32 -#define __INT_LEAST8_MAX__ 0x7f -#define __FLT32X_MAX_10_EXP__ 308 -#define __SIZEOF_INT128__ 16 -#define __LDBL_MAX_10_EXP__ 4932 -#define __ATOMIC_RELAXED 0 -#define __DBL_EPSILON__ double(2.22044604925031308084726333618164062e-16L) -#define __FLT128_MIN__ 3.36210314311209350626267781732175260e-4932F128 -#define _LP64 1 -#define __UINT8_C(c) c -#define __FLT64_MAX_EXP__ 1024 -#define __INT_LEAST32_TYPE__ int -#define __SIZEOF_WCHAR_T__ 4 -#define __FLT128_HAS_QUIET_NAN__ 1 -#define __INT_FAST8_TYPE__ signed char -#define __FLT64X_MIN__ 3.36210314311209350626267781732175260e-4932F64x -#define __GNUC_STDC_INLINE__ 1 -#define __FLT64_HAS_DENORM__ 1 -#define __FLT32_EPSILON__ 1.19209289550781250000000000000000000e-7F32 -#define __DBL_DECIMAL_DIG__ 17 -#define __STDC_UTF_32__ 1 -#define __INT_FAST8_WIDTH__ 8 -#define __FXSR__ 1 -#define __DEC_EVAL_METHOD__ 2 -#define __FLT32X_MAX__ 1.79769313486231570814527423731704357e+308F32x -#define __cpp_runtime_arrays 198712 -#define __UINT64_TYPE__ long unsigned int -#define __UINT32_C(c) c##U -#define __INTMAX_MAX__ 0x7fffffffffffffffL -#define __cpp_alias_templates 200704 -#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ -#define __FLT_DENORM_MIN__ 1.40129846432481707092372958328991613e-45F -#define __INT8_MAX__ 0x7f -#define __LONG_WIDTH__ 64 -#define __PIC__ 2 -#define __UINT_FAST32_TYPE__ long unsigned int -#define __CHAR32_TYPE__ unsigned int -#define __FLT_MAX__ 3.40282346638528859811704183484516925e+38F -#define __cpp_constexpr 201304 -#define __INT32_TYPE__ int -#define __SIZEOF_DOUBLE__ 8 -#define __cpp_exceptions 199711 -#define __FLT_MIN_10_EXP__ (-37) -#define __FLT64_MIN__ 2.22507385850720138309023271733240406e-308F64 -#define __INT_LEAST32_WIDTH__ 32 -#define __INTMAX_TYPE__ long int -#define __DEC128_MAX_EXP__ 6145 -#define __FLT32X_HAS_QUIET_NAN__ 1 -#define __ATOMIC_CONSUME 1 -#define __GNUC_MINOR__ 2 -#define __GLIBCXX_TYPE_INT_N_0 __int128 -#define __INT_FAST16_WIDTH__ 64 -#define __UINTMAX_MAX__ 0xffffffffffffffffUL -#define __DEC32_MANT_DIG__ 7 -#define __FLT32X_DENORM_MIN__ 4.94065645841246544176568792868221372e-324F32x -#define __DBL_MAX_10_EXP__ 308 -#define __LDBL_DENORM_MIN__ 3.64519953188247460252840593361941982e-4951L -#define __INT16_C(c) c -#define __cpp_generic_lambdas 201304 -#define __STDC__ 1 -#define __FLT32X_DIG__ 15 -#define __PTRDIFF_TYPE__ long int -#define __ATOMIC_SEQ_CST 5 -#define __UINT32_TYPE__ unsigned int -#define __FLT32X_MIN_10_EXP__ (-307) -#define __UINTPTR_TYPE__ long unsigned int -#define __DEC64_SUBNORMAL_MIN__ 0.000000000000001E-383DD -#define __DEC128_MANT_DIG__ 34 -#define __LDBL_MIN_10_EXP__ (-4931) -#define __FLT128_EPSILON__ 1.92592994438723585305597794258492732e-34F128 -#define __SSE_MATH__ 1 -#define __SIZEOF_LONG_LONG__ 8 -#define __cpp_user_defined_literals 200809 -#define __FLT128_DECIMAL_DIG__ 36 -#define __GCC_ATOMIC_LLONG_LOCK_FREE 2 -#define __FLT32X_MIN__ 2.22507385850720138309023271733240406e-308F32x -#define __LDBL_DIG__ 18 -#define __FLT_DECIMAL_DIG__ 9 -#define __UINT_FAST16_MAX__ 0xffffffffffffffffUL -#define __GCC_ATOMIC_SHORT_LOCK_FREE 2 -#define __INT_LEAST64_WIDTH__ 64 -#define __UINT_FAST8_TYPE__ unsigned char -#define _GNU_SOURCE 1 -#define __cpp_init_captures 201304 -#define __ATOMIC_ACQ_REL 4 -#define __ATOMIC_RELEASE 3 diff --git a/shared/qssquery.cpp b/shared/qssquery.cpp new file mode 100644 index 0000000..8484cbe --- /dev/null +++ b/shared/qssquery.cpp @@ -0,0 +1,286 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "qssquery.h" + +const QVector &QSSQuery::getTokens() const +{ + return tokens; +} + +const QVector &QSSQuery::getSortConditions() const +{ + return sortConditions; +} + +QueryType QSSQuery::getQueryType() +{ + return static_cast(tokensMask & COMBINED); +} + +bool QSSQuery::checkParanthesis(QString expression) +{ + QStack open; + QStack close; + + for(QChar &c : expression) + { + if(c == '(') + { + open.push(c); + } + if(c == ')') + { + close.push(c); + } + } + if(open.size() != close.size()) + { + return false; + } + while(!open.empty() && !close.empty()) + { + QChar o = open.pop(); + QChar c = close.pop(); + if(o != '(' && c != ')') + { + return false; + } + } + return true; +} + +std::optional fromString(QString fieldString) +{ + if(fieldString == "path" || fieldString == "file.path") + { + return FILE_PATH; + } + else if(fieldString == "mtime" || fieldString == "file.mtime") + { + return FILE_MTIME; + } + else if(fieldString == "size" || fieldString == "file.size") + { + return FILE_SIZE; + } + else if(fieldString == "content.text") + { + return CONTENT_TEXT; + } + else if(fieldString == "content.page" || fieldString == "page") + { + return CONTENT_TEXT_PAGE; + } + return {}; +} + +// sort:(mtime desc, page asc) +QVector createSortConditions(QString sortExpression) +{ + QVector result; + QStringList splitted_inner = sortExpression.split(","); + for(int i = 0; i < splitted_inner.length(); i++) + { + QStringList splitted = splitted_inner[i].split(" "); + if(splitted.length() < 1 || splitted.length() > 2) + { + throw QSSGeneralException("sort specifier must have format [field] (asc|desc)"); + } + + QString field = splitted[0]; + auto queryField = fromString(field); + if(!queryField) + { + throw QSSGeneralException("Unknown sort field supplied"); + } + + SortOrder order; + if(splitted.length() == 2) + { + QString orderstr = splitted[1]; + if(orderstr.compare("asc", Qt::CaseInsensitive) == 0) + { + order = ASC; + } + else if(orderstr.compare("desc", Qt::CaseInsensitive) == 0) + { + order = DESC; + } + else + { + throw QSSGeneralException("Unknown order specifier: " + order); + } + } + else + { + order = ASC; + } + + SortCondition condition; + condition.field = queryField.value(); + condition.order = order; + result.append(condition); + } + + return result; +} + +void QSSQuery::addToken(Token t) +{ + tokens.append(t); + tokensMask |= t.type; +} + +/* Builds the query from the supplied expression + * + * AND is the default boolean operator, when the user does not provide any + * thus, "Downloads zip" becomes essentailly "path.contains:(Downloads) AND path.contains:(zip)" + * + * TODO: It's a bit ugly still*/ +QSSQuery QSSQuery::build(QString expression) +{ + if(!checkParanthesis(expression)) + { + throw QSSGeneralException("Invalid paranthesis"); + } + + QSSQuery result; + // TODO: merge lonewords + QRegularExpression rx("((?(\\.|\\w)+):(?\\((?[^\\)]+)\\)|([\\w,])+)|(?AND|OR)" + "|(?!)|(?\\(|\\))|(?\\w+))"); + QRegularExpressionMatchIterator i = rx.globalMatch(expression); + auto previousWasBool = [&result] { return !result.tokens.empty() && ((result.tokens.last().type & BOOL) == BOOL); }; + auto previousWas = [&result](TokenType t) { return !result.tokens.empty() && (result.tokens.last().type == t); }; + + while(i.hasNext()) + { + QRegularExpressionMatch m = i.next(); + QString boolean = m.captured("boolean"); + QString negation = m.captured("negation"); + QString filtername = m.captured("filtername"); + QString bracket = m.captured("bracket"); + QString loneword = m.captured("loneword"); + + if(boolean != "") + { + if(previousWasBool()) + { + throw QSSGeneralException("Can't have two booleans following each other"); + } + if(previousWas(NEGATION)) + { + throw QSSGeneralException("Can't have a negation preceeding a boolean"); + } + if(boolean == "AND") + { + result.addToken(Token(BOOL_AND)); + } + else if(boolean == "OR") + { + result.addToken(Token(BOOL_OR)); + } + } + if(negation != "") + { + if(previousWas(NEGATION)) + { + throw QSSGeneralException("Can't have two negations following each other"); + } + if(!previousWasBool()) + { + result.addToken(Token(BOOL_AND)); // Implicit and, our default operation + } + result.addToken(Token(NEGATION)); + } + if(!result.tokens.isEmpty() && !previousWasBool() && !previousWas(NEGATION) && !previousWas(BRACKET_OPEN) && + bracket != ")") + { + // the current token isn't a negation, isn't a boolean. Thus, implicit AND is required + result.addToken(Token(BOOL_AND)); + } + + if(bracket != "") + { + if(bracket == "(") + { + result.addToken(Token(BRACKET_OPEN)); + } + else + { + result.addToken(Token(BRACKET_CLOSE)); + } + } + + if(loneword != "") + { + result.addToken(Token(FILTER_PATH_CONTAINS, loneword)); + } + + if(filtername != "") + { + TokenType tokenType; + QString value = m.captured("innerargs"); + if(value == "") + { + value = m.captured("args"); + } + + if(filtername == "path.contains") + { + tokenType = FILTER_PATH_CONTAINS; + } + else if(filtername == "path.starts") + { + tokenType = FILTER_PATH_STARTS; + } + else if(filtername == "path.ends") + { + tokenType = FILTER_PATH_ENDS; + } + else if(filtername == "file.size" || filtername == "size") + { + tokenType = FILTER_PATH_SIZE; + } + else if(filtername == "c" || filtername == "contains") + { + tokenType = FILTER_CONTENT_CONTAINS; + } + else if(filtername == "page" || filtername == "content.page") + { + tokenType = FILTER_CONTENT_PAGE; + } + else if(filtername == + "sort") // TODO: given this is not really a "filter", this feels slightly misplaced here + { + if(!result.sortConditions.empty()) + { + throw QSSGeneralException("Two sort statements are illegal"); + } + result.sortConditions = createSortConditions(value); + continue; + } + else + { + throw QSSGeneralException("Unknown filter provided!"); + } + result.addToken(Token(tokenType, value)); + } + } + + bool contentsearch = result.getTokensMask() & FILTER_CONTENT == FILTER_CONTENT; + bool sortsForContent = std::any_of(result.sortConditions.begin(), result.sortConditions.end(), + [](SortCondition c) { return c.field == CONTENT_TEXT; }); + + if(!contentsearch && sortsForContent) + { + throw QSSGeneralException("We cannot sort by text if we don't search for it"); + } + + return result; +} diff --git a/shared/qssquery.h b/shared/qssquery.h new file mode 100644 index 0000000..4f1e35b --- /dev/null +++ b/shared/qssquery.h @@ -0,0 +1,59 @@ +#ifndef QSSQUERY_H +#define QSSQUERY_H +#include +#include +#include "qssgeneralexception.h" +#include "token.h" +/* Fields that can be queried or sorted */ +enum QueryField +{ + FILE_PATH, + FILE_MTIME, + FILE_SIZE, + CONTENT_TEXT, + CONTENT_TEXT_PAGE +}; + +enum SortOrder +{ + ASC, + DESC +}; + +struct SortCondition +{ + QueryField field; + SortOrder order; +}; + +enum QueryType +{ + NOTHING = 0, + PATH_ONLY = FILTER_PATH, + CONTENT_ONLY = FILTER_CONTENT, + COMBINED = PATH_ONLY | CONTENT_ONLY +}; + +class QSSQuery +{ + private: + /* Helper field to determine quertype as well as to quickly check what kind of filters etc. + * are being used in this query*/ + int tokensMask; + QVector tokens; + QVector sortConditions; + void addToken(Token t); + + public: + const QVector &getTokens() const; + const QVector &getSortConditions() const; + QueryType getQueryType(); + int getTokensMask() const + { + return tokensMask; + } + static bool checkParanthesis(QString query); + static QSSQuery build(QString query); +}; + +#endif // QSSQUERY_H diff --git a/shared/shared.pro b/shared/shared.pro index 786e3a4..3b53026 100644 --- a/shared/shared.pro +++ b/shared/shared.pro @@ -11,6 +11,7 @@ QT -= gui TARGET = shared TEMPLATE = lib CONFIG += staticlib +CONFIG += c++17 # The following define makes your compiler emit warnings if you use # any feature of Qt which has been marked as deprecated (the exact warnings @@ -24,12 +25,15 @@ DEFINES += QT_DEPRECATED_WARNINGS #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += sqlitesearch.cpp \ - qssgeneralexception.cpp + qssgeneralexception.cpp \ + qssquery.cpp HEADERS += sqlitesearch.h \ filedata.h \ searchresult.h \ - qssgeneralexception.h + qssgeneralexception.h \ + token.h \ + qssquery.h unix { target.path = /usr/lib INSTALLS += target diff --git a/shared/sqlitesearch.cpp b/shared/sqlitesearch.cpp index ff64fc9..f43bb0e 100644 --- a/shared/sqlitesearch.cpp +++ b/shared/sqlitesearch.cpp @@ -12,217 +12,134 @@ SqliteSearch::SqliteSearch(QSqlDatabase &db) this->db = &db; } -QVector SqliteSearch::tokenize(QString expression) +QString SqliteSearch::fieldToColumn(QueryField field) { - if(!checkParanthesis(expression)) - { - throw QSSGeneralException("Invalid paranthesis"); - } - // TODO: merge lonewords - QVector result; - QRegularExpression rx("((?(\\.|\\w)+):(?\\((?[^\\)]+)\\)|([\\w,])+)|(?AND|OR|" - "!)|(?\\(|\\))|(?\\w+))"); - QRegularExpressionMatchIterator i = rx.globalMatch(expression); - auto isSort = [](QString &key) { return key == "sort"; }; - auto isBool = [](QString &key) { return key == "AND" || key == "OR" || key == "!"; }; - while(i.hasNext()) - { - QRegularExpressionMatch m = i.next(); - QString boolean = m.captured("boolean"); - QString filtername = m.captured("filtername"); - QString bracket = m.captured("bracket"); - QString loneword = m.captured("loneword"); - - if(boolean != "") - { - result.append(Token(boolean)); - } - - if(!result.empty()) - { - QString &lastKey = result.last().key; - if(!isBool(lastKey) && !isSort(lastKey) && !isSort(filtername)) - { - result.append(Token("AND")); - } - } - - if(bracket != "") - { - if(bracket == "(") - { - result.append(Token("AND")); - } - result.append(Token(bracket)); - } - - if(loneword != "") - { - result.append(Token("path.contains", loneword)); - } - - if(filtername != "") - { - QString value = m.captured("innerargs"); - if(value == "") - { - value = m.captured("args"); - } - result.append(Token(filtername, value)); - } - } - return result; -} - -QString SqliteSearch::fieldToColumn(QString field) -{ - if(field == "mtime" || field == "file.mtime") + if(field == FILE_MTIME) { return "file.mtime"; } - else if(field == "page" || field == "content.page") - { - return "content.page"; - } - else if(field == "path" || field == "file.path") + else if(field == FILE_PATH) { return "file.path"; } - else if(field == "size" || field == "file.size") + else if(field == FILE_SIZE) { return "file.size"; } + else if(field == CONTENT_TEXT_PAGE) + { + return "content.page"; + } + else if(field == CONTENT_TEXT) + { + return "content.text"; + } return ""; } -QString SqliteSearch::createSortSql(const SqliteSearch::Token &token) +QString SqliteSearch::createSortSql(const QVector sortConditions) { - // sort:(mtime desc, page asc) - if(token.key == "sort") + QString sortsql; + for(const SortCondition &sc : sortConditions) { - QString sortsql; - QStringList splitted_inner = token.value.split(","); - for(int i = 0; i < splitted_inner.length(); i++) + QString order; + QString field = fieldToColumn(sc.field); + if(field == "") { - QStringList splitted = splitted_inner[i].split(" "); - if(splitted.length() < 1 || splitted.length() > 2) - { - throw QSSGeneralException("sort specifier must have format [field] (asc|desc)"); - } - - QString field = splitted[0]; - field = fieldToColumn(field); - if(field == "") - { - throw QSSGeneralException("Unknown sort field supplied"); - } - - QString order; - if(splitted.length() == 2) - { - order = splitted[1]; - if(order.compare("asc", Qt::CaseInsensitive) == 0) - { - order = "ASC"; - } - else if(order.compare("desc", Qt::CaseInsensitive) == 0) - { - order = "DESC"; - } - else - { - throw QSSGeneralException("Unknown order specifier: " + order); - } - } - else - { - order = "ASC"; - } - - sortsql += field + " " + order; - if(splitted_inner.length() - i > 1) - { - sortsql += ", "; - } + throw QSSGeneralException("Unknown sort field supplied"); } + if(sc.order == DESC) + { + order = "DESC"; + } + else + { + order = "ASC"; + } + sortsql += field + " " + order + ", "; + } + sortsql.chop(2); + if(!sortsql.isEmpty()) + { return " ORDER BY " + sortsql; } return ""; } -QPair> SqliteSearch::createSql(const SqliteSearch::Token &token) +QPair> createNonArgPair(QString key) +{ + return {" " + key + " ", QVector()}; +} + +QPair> SqliteSearch::createSql(const Token &token) { QPair> result; - - QString key = token.key; QString value = token.value; value = value.replace("'", "\\'"); - if(key == "AND" || key == "OR" || key == "(" || key == ")") + + if(token.type == BOOL_AND) { - return {" " + key + " ", QVector()}; + return createNonArgPair("AND"); } - if(key == "!") + if(token.type == BOOL_OR) { - return {" NOT ", QVector()}; + return createNonArgPair("OR"); } - if(key == "path.starts") + if(token.type == NEGATION) + { + return createNonArgPair("NOT"); + } + if(token.type == BRACKET_OPEN) + { + return createNonArgPair("("); + } + if(token.type == BRACKET_CLOSE) + { + return createNonArgPair(")"); + } + if(token.type == FILTER_PATH_STARTS) { return {" file.path LIKE ? || '%' ", {value}}; } - if(key == "path.ends") + if(token.type == FILTER_PATH_ENDS) { return {" file.path LIKE '%' || ? ", {value}}; } - if(key == "path.contains" || key == "inpath") + if(token.type == FILTER_PATH_CONTAINS) { return {" file.path LIKE '%' || ? || '%' ", {value}}; } - if(key == "page") + if(token.type == FILTER_CONTENT_PAGE) { return {" content.page = ?", {value}}; } - if(key == "contains" || key == "c") + if(token.type == FILTER_CONTENT_CONTAINS) { return {" content.id IN (SELECT content_fts.ROWID FROM content_fts WHERE content_fts.content MATCH ?) ", {value}}; } - throw QSSGeneralException("Unknown token: " + key); + throw QSSGeneralException("Unknown token passed (should not happen)"); } -QSqlQuery SqliteSearch::makeSqlQuery(const QVector &tokens) +QSqlQuery SqliteSearch::makeSqlQuery(const QSSQuery &query) { QString whereSql; - QString limitSql; - QString sortSql; QVector bindValues; - bool isContentSearch = false; - for(const Token &c : tokens) - { - if(c.key == "sort") - { - if(sortSql != "") - { - throw QSSGeneralException("Invalid input: Two seperate sort statements are invalid"); - } - sortSql = createSortSql(c); - } - else - { - if(c.key == "c" || c.key == "contains") - { - isContentSearch = true; - } - auto sql = createSql(c); - whereSql += sql.first; - bindValues.append(sql.second); - } - } - - QString prepSql; - if(whereSql.isEmpty()) + bool isContentSearch = query.getTokensMask() & FILTER_CONTENT == FILTER_CONTENT; + if(query.getTokens().isEmpty()) { throw QSSGeneralException("Nothing to search for supplied"); } + + for(const Token &token : query.getTokens()) + { + auto sql = createSql(token); + whereSql += sql.first; + bindValues.append(sql.second); + } + + QString prepSql; + QString sortSql = createSortSql(query.getSortConditions()); if(isContentSearch) { if(sortSql.isEmpty()) @@ -240,11 +157,6 @@ QSqlQuery SqliteSearch::makeSqlQuery(const QVector &tokens) { sortSql = "ORDER BY file.mtime DESC"; } - if(sortSql.contains("content.")) - { - throw QSSGeneralException("Cannot sort for content fields when not doing a content search"); - } - prepSql = "SELECT file.path AS path, '0' as pages, file.mtime AS mtime, file.size AS size, file.filetype AS " "filetype FROM file WHERE 1=1 AND " + whereSql + " " + sortSql; @@ -252,7 +164,6 @@ QSqlQuery SqliteSearch::makeSqlQuery(const QVector &tokens) QSqlQuery dbquery(*db); dbquery.prepare(prepSql); - for(const QString &value : bindValues) { if(value != "") @@ -263,10 +174,10 @@ QSqlQuery SqliteSearch::makeSqlQuery(const QVector &tokens) return dbquery; } -QVector SqliteSearch::search(const QString &query) +QVector SqliteSearch::search(const QSSQuery &query) { QVector results; - QSqlQuery dbQuery = makeSqlQuery(tokenize(query)); + QSqlQuery dbQuery = makeSqlQuery(query); bool success = dbQuery.exec(); if(!success) { @@ -296,35 +207,3 @@ QVector SqliteSearch::search(const QString &query) } return results; } - -bool SqliteSearch::checkParanthesis(QString expression) -{ - QStack open; - QStack close; - - for(QChar &c : expression) - { - if(c == '(') - { - open.push(c); - } - if(c == ')') - { - close.push(c); - } - } - if(open.size() != close.size()) - { - return false; - } - while(!open.empty() && !close.empty()) - { - QChar o = open.pop(); - QChar c = close.pop(); - if(o != '(' && c != ')') - { - return false; - } - } - return true; -} diff --git a/shared/sqlitesearch.h b/shared/sqlitesearch.h index ccdfe82..f3da328 100644 --- a/shared/sqlitesearch.h +++ b/shared/sqlitesearch.h @@ -3,34 +3,21 @@ #include #include #include "searchresult.h" - +#include "token.h" +#include "../shared/qssquery.h" class SqliteSearch { - class Token - { - public: - QString key; - QString value; - - Token(QString key = "", QString value = "") - { - this->key = key; - this->value = value; - } - }; public: SqliteSearch(QSqlDatabase &db); - QVector search(const QString &query); - static bool checkParanthesis(QString expression); + QVector search(const QSSQuery &query); private: QSqlDatabase *db; - QVector tokenize(QString expression); - QSqlQuery makeSqlQuery(const QVector &tokens); - QString fieldToColumn(QString col); + QSqlQuery makeSqlQuery(const QSSQuery &query); + QString fieldToColumn(QueryField field); QPair> createSql(const Token &token); - QString createSortSql(const SqliteSearch::Token &token); + QString createSortSql(const QVector sortConditions); }; #endif // SQLITESEARCH_H diff --git a/shared/token.cpp b/shared/token.cpp new file mode 100644 index 0000000..df2e737 --- /dev/null +++ b/shared/token.cpp @@ -0,0 +1,5 @@ +#include "token.h" + +Token::Token() +{ +} diff --git a/shared/token.h b/shared/token.h new file mode 100644 index 0000000..c8d2c21 --- /dev/null +++ b/shared/token.h @@ -0,0 +1,48 @@ +#ifndef TOKEN_H +#define TOKEN_H +#include + +enum TokenType +{ + WORD, + NEGATION = 2, + BOOL = 4, + BOOL_AND, + BOOL_OR, + GROUP = 8, + BRACKET_OPEN, + BRACKET_CLOSE, + SORT = 16, + FILTER_PATH = 32, + FILTER_PATH_MTIME, + FILTER_PATH_CONTAINS, + FILTER_PATH_SIZE, + FILTER_PATH_ENDS, + FILTER_PATH_STARTS, + FILTER_CONTENT = 64, + FILTER_CONTENT_CONTAINS, + FILTER_CONTENT_PAGE, +}; + +class Token +{ + public: + Token() + { + } + Token(TokenType type) + { + this->type = type; + } + + Token(TokenType type, QString value) + { + this->type = type; + this->value = value; + } + + TokenType type; + QString value; +}; + +#endif // TOKEN_H