مقایسه کامیتها
9 کامیتها
a3cfb7ade1
...
a415643923
مولف | SHA1 | تاریخ | |
---|---|---|---|
a415643923 | |||
b8c7514142 | |||
35bcd35ec9 | |||
ba81551a2c | |||
d8a205fbe5 | |||
ed4228326e | |||
2bb26bc63c | |||
5272365e5a | |||
5c899af26f |
@ -15,6 +15,7 @@ DEFINES += QT_DEPRECATED_WARNINGS
|
||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
SOURCES += \
|
||||
commandtag.cpp \
|
||||
main.cpp \
|
||||
commandadd.cpp \
|
||||
commanddelete.cpp \
|
||||
@ -27,6 +28,7 @@ HEADERS += \
|
||||
command.h \
|
||||
commandadd.h \
|
||||
commanddelete.h \
|
||||
commandtag.h \
|
||||
commandupdate.h \
|
||||
commandsearch.h \
|
||||
commandlist.h
|
||||
|
@ -2,7 +2,6 @@
|
||||
#include <QThread>
|
||||
#include <QDebug>
|
||||
#include "command.h"
|
||||
#include "looqsgeneralexception.h"
|
||||
|
||||
void Command::execute()
|
||||
{
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include <QCommandLineParser>
|
||||
#include "commandsearch.h"
|
||||
#include "databasefactory.h"
|
||||
#include "logger.h"
|
||||
|
||||
int CommandSearch::handle(QStringList arguments)
|
||||
|
65
cli/commandtag.cpp
Normal file
65
cli/commandtag.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
#include <QCommandLineParser>
|
||||
#include "commandtag.h"
|
||||
#include "logger.h"
|
||||
|
||||
int CommandTag::handle(QStringList arguments)
|
||||
{
|
||||
QCommandLineParser parser;
|
||||
parser.addPositionalArgument("add", "Adds a tag to a file",
|
||||
"add [tag] [paths...]. Adds the tag to the specified paths");
|
||||
parser.addPositionalArgument("remove", "Removes a file associated to tag", "remove [tag] [file]");
|
||||
parser.addPositionalArgument("delete", "Deletes a tag", "delete [tag]");
|
||||
parser.addPositionalArgument("list", "Lists paths associated with a tag, or all tags", "list [tag]");
|
||||
parser.addHelpOption();
|
||||
|
||||
parser.parse(arguments);
|
||||
|
||||
QStringList args = parser.positionalArguments();
|
||||
if(args.length() == 0)
|
||||
{
|
||||
parser.showHelp(EXIT_FAILURE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
QString cmd = args[0];
|
||||
qDebug() << cmd;
|
||||
if(cmd == "add")
|
||||
{
|
||||
if(args.length() < 3)
|
||||
{
|
||||
Logger::error() << "Not enough arguments provided. 'add' requires a tag followed by at least one path"
|
||||
<< Qt::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
QString tag = args[1];
|
||||
auto paths = args.mid(2).toVector();
|
||||
for(int i = 0; i < paths.size(); i++)
|
||||
{
|
||||
QFileInfo info{paths[i]};
|
||||
if(!info.exists())
|
||||
{
|
||||
Logger::error() << "Can't add tag for file " + info.absoluteFilePath() + " because it does not exist"
|
||||
<< Qt::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
QString absolutePath = info.absoluteFilePath();
|
||||
if(!this->dbService->fileExistsInDatabase(absolutePath))
|
||||
{
|
||||
Logger::error() << "Only files that have been indexed can be tagged. File not in index: " + absolutePath
|
||||
<< Qt::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
paths[i] = absolutePath;
|
||||
}
|
||||
|
||||
bool result = this->dbService->addTag(tag, paths);
|
||||
if(!result)
|
||||
{
|
||||
Logger::error() << "Failed to assign tags" << Qt::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
13
cli/commandtag.h
Normal file
13
cli/commandtag.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef COMMANDTAG_H
|
||||
#define COMMANDTAG_H
|
||||
#include "command.h"
|
||||
|
||||
class CommandTag : public Command
|
||||
{
|
||||
public:
|
||||
using Command::Command;
|
||||
|
||||
int handle(QStringList arguments) override;
|
||||
};
|
||||
|
||||
#endif // COMMANDTAG_H
|
@ -21,6 +21,7 @@
|
||||
#include "commandupdate.h"
|
||||
#include "commandsearch.h"
|
||||
#include "commandlist.h"
|
||||
#include "commandtag.h"
|
||||
#include "databasefactory.h"
|
||||
#include "logger.h"
|
||||
#include "sandboxedprocessor.h"
|
||||
@ -31,7 +32,7 @@
|
||||
void printUsage(QString argv0)
|
||||
{
|
||||
qInfo() << "Usage:" << argv0 << "command";
|
||||
qInfo() << "Valid commands: add, update, delete, search, list. Each command has a --help option.";
|
||||
qInfo() << "Valid commands: add, update, search, delete, tag, list. Each command has a --help option.";
|
||||
}
|
||||
|
||||
Command *commandFromName(QString name, SqliteDbService &dbService)
|
||||
@ -56,6 +57,10 @@ Command *commandFromName(QString name, SqliteDbService &dbService)
|
||||
{
|
||||
return new CommandList(dbService);
|
||||
}
|
||||
if(name == "tag")
|
||||
{
|
||||
return new CommandTag(dbService);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -193,7 +193,7 @@ int main(int argc, char *argv[])
|
||||
Logger::error() << error << Qt::endl;
|
||||
QMessageBox::critical(nullptr, "Error during upgrade",
|
||||
error);
|
||||
qApp->quit();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
);
|
||||
|
@ -877,6 +877,8 @@ void MainWindow::handleSearchResults(const QVector<SearchResult> &results)
|
||||
makePreviews(1);
|
||||
}
|
||||
|
||||
ui->tabWidget->setTabEnabled(1, previewDirty);
|
||||
|
||||
QString statusText = "Results: " + QString::number(results.size()) + " files";
|
||||
statusText += ", previewable: " + QString::number(this->previewCoordinator.previewableCount());
|
||||
if(hasDeleted)
|
||||
|
@ -25,10 +25,22 @@ SaveFileResult FileSaver::addFile(QString path)
|
||||
QString absPath = info.absoluteFilePath();
|
||||
|
||||
auto mtime = info.lastModified().toSecsSinceEpoch();
|
||||
if(this->dbService->fileExistsInDatabase(absPath, mtime))
|
||||
|
||||
bool exists = false;
|
||||
if(this->fileSaverOptions.fillExistingContentless)
|
||||
{
|
||||
exists = this->dbService->fileExistsInDatabase(absPath, mtime, 'c');
|
||||
}
|
||||
else
|
||||
{
|
||||
exists = this->dbService->fileExistsInDatabase(absPath, mtime);
|
||||
}
|
||||
|
||||
if(exists)
|
||||
{
|
||||
return SKIPPED;
|
||||
}
|
||||
|
||||
return saveFile(info);
|
||||
}
|
||||
|
||||
@ -134,10 +146,7 @@ SaveFileResult FileSaver::saveFile(const QFileInfo &fileInfo)
|
||||
if(mustFillContent)
|
||||
{
|
||||
auto filetype = this->dbService->queryFileType(fileInfo.absolutePath());
|
||||
if(filetype)
|
||||
{
|
||||
mustFillContent = filetype.value() == 'c';
|
||||
}
|
||||
mustFillContent = !filetype.has_value() || filetype.value() == 'c';
|
||||
}
|
||||
}
|
||||
|
||||
|
6
shared/migrations/5.sql
Normal file
6
shared/migrations/5.sql
Normal file
@ -0,0 +1,6 @@
|
||||
CREATE TABLE tag(id integer PRIMARY KEY, name varchar(128) UNIQUE);
|
||||
CREATE TABLE filetag(fileid integer, tagid integer);
|
||||
CREATE INDEX filetag_fileid ON filetag(fileid);
|
||||
CREATE INDEX tag_id ON tag(id);
|
||||
CREATE INDEX file_path ON file ( path );
|
||||
UPDATE file SET filetype='c' WHERE filetype='f';
|
@ -4,5 +4,6 @@
|
||||
<file>2.sql</file>
|
||||
<file>3.sql</file>
|
||||
<file>4.sql</file>
|
||||
<file>5.sql</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@ -2,25 +2,10 @@
|
||||
#include <QFileInfo>
|
||||
#include <QDateTime>
|
||||
#include <QSqlError>
|
||||
#include "looqsgeneralexception.h"
|
||||
#include "sqlitedbservice.h"
|
||||
#include "filedata.h"
|
||||
#include "logger.h"
|
||||
bool SqliteDbService::fileExistsInDatabase(QString path, qint64 mtime)
|
||||
{
|
||||
auto query = QSqlQuery(dbFactory->forCurrentThread());
|
||||
query.prepare("SELECT 1 FROM file WHERE path = ? and mtime = ?");
|
||||
query.addBindValue(path);
|
||||
query.addBindValue(mtime);
|
||||
if(!query.exec())
|
||||
{
|
||||
throw LooqsGeneralException("Error while trying to query for file existance: " + query.lastError().text());
|
||||
}
|
||||
if(!query.next())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return query.value(0).toBool();
|
||||
}
|
||||
|
||||
QVector<SearchResult> SqliteDbService::search(const LooqsQuery &query)
|
||||
{
|
||||
@ -31,13 +16,7 @@ QVector<SearchResult> SqliteDbService::search(const LooqsQuery &query)
|
||||
|
||||
std::optional<QChar> SqliteDbService::queryFileType(QString absPath)
|
||||
{
|
||||
auto query = QSqlQuery(dbFactory->forCurrentThread());
|
||||
query.prepare("SELECT filetype FROM file WHERE path = ?");
|
||||
query.addBindValue(absPath);
|
||||
if(!query.exec())
|
||||
{
|
||||
throw LooqsGeneralException("Error while trying to query for file type: " + query.lastError().text());
|
||||
}
|
||||
auto query = exec("SELECT filetype FROM file WHERE path = ?", {absPath});
|
||||
if(!query.next())
|
||||
{
|
||||
return {};
|
||||
@ -47,18 +26,17 @@ std::optional<QChar> SqliteDbService::queryFileType(QString absPath)
|
||||
|
||||
bool SqliteDbService::fileExistsInDatabase(QString path)
|
||||
{
|
||||
auto query = QSqlQuery(dbFactory->forCurrentThread());
|
||||
query.prepare("SELECT 1 FROM file WHERE path = ?");
|
||||
query.addBindValue(path);
|
||||
if(!query.exec())
|
||||
{
|
||||
throw LooqsGeneralException("Error while trying to query for file existance: " + query.lastError().text());
|
||||
}
|
||||
if(!query.next())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return query.value(0).toBool();
|
||||
return execBool("SELECT 1 FROM file WHERE path = ?", {path});
|
||||
}
|
||||
|
||||
bool SqliteDbService::fileExistsInDatabase(QString path, qint64 mtime)
|
||||
{
|
||||
return execBool("SELECT 1 FROM file WHERE path = ? AND mtime = ?", {path, mtime});
|
||||
}
|
||||
|
||||
bool SqliteDbService::fileExistsInDatabase(QString path, qint64 mtime, QChar fileType)
|
||||
{
|
||||
return execBool("SELECT 1 FROM file WHERE path = ? AND mtime = ? AND filetype = ?", {path, mtime, fileType});
|
||||
}
|
||||
|
||||
SqliteDbService::SqliteDbService(DatabaseFactory &dbFactory)
|
||||
@ -164,6 +142,31 @@ bool SqliteDbService::insertToFTS(bool useTrigrams, QSqlDatabase &db, int fileid
|
||||
return true;
|
||||
}
|
||||
|
||||
QSqlQuery SqliteDbService::exec(QString querystr, std::initializer_list<QVariant> args)
|
||||
{
|
||||
auto query = QSqlQuery(dbFactory->forCurrentThread());
|
||||
query.prepare(querystr);
|
||||
for(const QVariant &v : args)
|
||||
{
|
||||
query.addBindValue(v);
|
||||
}
|
||||
if(!query.exec())
|
||||
{
|
||||
throw LooqsGeneralException("Error while exec(): " + query.lastError().text() + " for query: " + querystr);
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
bool SqliteDbService::execBool(QString querystr, std::initializer_list<QVariant> args)
|
||||
{
|
||||
auto query = exec(querystr, args);
|
||||
if(!query.next())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return query.value(0).toBool();
|
||||
}
|
||||
|
||||
SaveFileResult SqliteDbService::saveFile(QFileInfo fileInfo, QVector<PageData> &pageData, bool pathsOnly)
|
||||
{
|
||||
QString absPath = fileInfo.absoluteFilePath();
|
||||
@ -231,3 +234,56 @@ SaveFileResult SqliteDbService::saveFile(QFileInfo fileInfo, QVector<PageData> &
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool SqliteDbService::addTag(QString tag, QString path)
|
||||
{
|
||||
QVector<QString> paths;
|
||||
paths.append(path);
|
||||
return addTag(tag, paths);
|
||||
}
|
||||
|
||||
bool SqliteDbService::addTag(QString tag, const QVector<QString> &paths)
|
||||
{
|
||||
QSqlDatabase db = dbFactory->forCurrentThread();
|
||||
QSqlQuery tagQuery(db);
|
||||
QSqlQuery fileTagQuery(db);
|
||||
|
||||
tagQuery.prepare("INSERT OR IGNORE INTO tag (name) VALUES(?)");
|
||||
tagQuery.addBindValue(tag);
|
||||
|
||||
fileTagQuery.prepare("INSERT INTO filetag(fileid, tagid) VALUES((SELECT id FROM file WHERE path = ?), (SELECT id "
|
||||
"FROM tag WHERE name = ?))");
|
||||
fileTagQuery.bindValue(1, tag);
|
||||
if(!db.transaction())
|
||||
{
|
||||
Logger::error() << "Failed to open transaction to add paths for tag " << tag << " : " << db.lastError()
|
||||
<< Qt::endl;
|
||||
return false;
|
||||
}
|
||||
if(!tagQuery.exec())
|
||||
{
|
||||
db.rollback();
|
||||
Logger::error() << "Failed INSERT query" << tagQuery.lastError() << Qt::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
for(const QString &path : paths)
|
||||
{
|
||||
fileTagQuery.bindValue(0, path);
|
||||
if(!fileTagQuery.exec())
|
||||
{
|
||||
db.rollback();
|
||||
Logger::error() << "Failed to add paths to tag" << Qt::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!db.commit())
|
||||
{
|
||||
db.rollback();
|
||||
Logger::error() << "Failed to commit tag insertion transaction" << db.lastError() << Qt::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -17,6 +17,9 @@ class SqliteDbService
|
||||
DatabaseFactory *dbFactory = nullptr;
|
||||
bool insertToFTS(bool useTrigrams, QSqlDatabase &db, int fileid, QVector<PageData> &pageData);
|
||||
|
||||
QSqlQuery exec(QString query, std::initializer_list<QVariant> args);
|
||||
bool execBool(QString querystr, std::initializer_list<QVariant> args);
|
||||
|
||||
public:
|
||||
SqliteDbService(DatabaseFactory &dbFactory);
|
||||
SaveFileResult saveFile(QFileInfo fileInfo, QVector<PageData> &pageData, bool pathsOnly);
|
||||
@ -24,6 +27,9 @@ class SqliteDbService
|
||||
bool deleteFile(QString path);
|
||||
bool fileExistsInDatabase(QString path);
|
||||
bool fileExistsInDatabase(QString path, qint64 mtime);
|
||||
bool fileExistsInDatabase(QString path, qint64 mtime, QChar filetype);
|
||||
bool addTag(QString tag, QString path);
|
||||
bool addTag(QString tag, const QVector<QString> &paths);
|
||||
QVector<SearchResult> search(const LooqsQuery &query);
|
||||
|
||||
std::optional<QChar> queryFileType(QString absPath);
|
||||
|
بارگذاری…
مرجع در شماره جدید
Block a user