diff --git a/SQLiteStudio3/Tests/TestUtils/configmock.cpp b/SQLiteStudio3/Tests/TestUtils/configmock.cpp index f5ce5c586a..5f08ec0e62 100644 --- a/SQLiteStudio3/Tests/TestUtils/configmock.cpp +++ b/SQLiteStudio3/Tests/TestUtils/configmock.cpp @@ -231,6 +231,15 @@ void ConfigMock::refreshDdlHistory() { } +QList > ConfigMock::getScriptFunctions() +{ + return QList >(); +} + +void ConfigMock::setScriptFunctions(const QList >&) +{ +} + QString ConfigMock::getSqlite3Version() const { return "3.8.8"; diff --git a/SQLiteStudio3/Tests/TestUtils/configmock.h b/SQLiteStudio3/Tests/TestUtils/configmock.h index 620548b548..6be8f8ab71 100644 --- a/SQLiteStudio3/Tests/TestUtils/configmock.h +++ b/SQLiteStudio3/Tests/TestUtils/configmock.h @@ -47,6 +47,8 @@ class ConfigMock : public Config QList getDdlHistoryFor(const QString&, const QString&, const QDate&); DdlHistoryModel* getDdlHistoryModel(); void clearDdlHistory(); + QList > getScriptFunctions(); + void setScriptFunctions(const QList >&); void begin(); void commit(); void rollback(); diff --git a/SQLiteStudio3/coreSQLiteStudio/services/config.h b/SQLiteStudio3/coreSQLiteStudio/services/config.h index bd001c2714..36696e27aa 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/config.h +++ b/SQLiteStudio3/coreSQLiteStudio/services/config.h @@ -12,7 +12,7 @@ #include #include -const int SQLITESTUDIO_CONFIG_VERSION = 3; +const int SQLITESTUDIO_CONFIG_VERSION = 4; CFG_CATEGORIES(Core, CFG_CATEGORY(General, @@ -29,7 +29,6 @@ CFG_CATEGORIES(Core, CFG_ENTRY(int, HistorySize, 100) ) CFG_CATEGORY(Internal, - CFG_ENTRY(QVariantList, Functions, QVariantList()) CFG_ENTRY(QVariantList, Collations, QVariantList()) CFG_ENTRY(QVariantList, Extensions, QVariantList()) CFG_ENTRY(QVariantList, CodeSnippets, QVariantList()) @@ -185,6 +184,9 @@ class API_EXPORT Config : public QObject virtual void deleteReport(int id) = 0; virtual void clearReportHistory() = 0; + virtual QList > getScriptFunctions() = 0; + virtual void setScriptFunctions(const QList >& newFunctions) = 0; + virtual void begin() = 0; virtual void commit() = 0; virtual void rollback() = 0; diff --git a/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.cpp b/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.cpp index 9829ab64e3..49383ddef9 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.cpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include @@ -616,6 +618,12 @@ QString ConfigImpl::getLegacyConfigPath() #endif } +void ConfigImpl::dropTables(const QList& tables) +{ + for (const QString& table : tables) + db->exec("DROP TABLE " + table); +} + void ConfigImpl::initTables() { SqlQueryPtr results = db->exec("SELECT lower(name) AS name FROM sqlite_master WHERE type = 'table'"); @@ -623,9 +631,7 @@ void ConfigImpl::initTables() if (!tables.contains("version")) { - for (const QString& table : tables) - db->exec("DROP TABLE "+table); - + dropTables(tables); tables.clear(); db->exec("CREATE TABLE version (version NUMERIC)"); db->exec("INSERT INTO version VALUES ("+QString::number(SQLITESTUDIO_CONFIG_VERSION)+")"); @@ -682,6 +688,10 @@ void ConfigImpl::initTables() if (!tables.contains("reports_history")) db->exec("CREATE TABLE reports_history (id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER, feature_request BOOLEAN, title TEXT, url TEXT)"); + + if (!tables.contains("script_functions")) + db->exec("CREATE TABLE script_functions (name TEXT, lang TEXT, code TEXT, \"initCode\" TEXT, \"finalCode\" TEXT, databases TEXT, arguments TEXT," + " \"type\" INTEGER, \"undefinedArgs\" BOOLEAN, \"allDatabases\" BOOLEAN, deterministic BOOLEAN)"); } void ConfigImpl::initDbFile() @@ -1128,6 +1138,29 @@ void ConfigImpl::updateConfigDb() { // 2->3 db->exec("ALTER TABLE groups ADD db_expanded INTEGER DEFAULT 0"); + Q_FALLTHROUGH(); + } + case 3: + { + // 3->4 + QVariant oldFuncs = get("Internal", "Functions"); + if (oldFuncs.isValid() && !oldFuncs.isNull()) + { + for (const QVariant& var : oldFuncs.toList()) + { + QHash fnHash = var.toHash(); + db->exec("INSERT INTO script_functions" + " (name, lang, code, \"initCode\", \"finalCode\", databases, arguments, \"type\", \"undefinedArgs\", \"allDatabases\", deterministic)" + " VALUES (?, REPLACE(?, 'QtScript', 'JavaScript'), ?, ?, ?, ?, ?, ?, ?, ?, ?)", + { fnHash["name"].toString(), fnHash["lang"].toString(), + fnHash["code"].toString(), fnHash["initCode"].toString(), fnHash["finalCode"].toString(), + QString::fromUtf8(QJsonDocument(QJsonArray::fromVariantList(fnHash["databases"].toList())).toJson(QJsonDocument::Compact)), + QString::fromUtf8(QJsonDocument(QJsonArray::fromVariantList(fnHash["arguments"].toList())).toJson(QJsonDocument::Compact)), + fnHash["type"].toInt(), fnHash["undefinedArgs"].toBool(), fnHash["allDatabases"].toBool(), + fnHash["deterministic"].toBool() }); + } + } + db->exec("DELETE FROM settings WHERE [group] = 'Internal' AND [key] = 'Functions'"); } // Add cases here for next versions, // without a "break" instruction, @@ -1174,3 +1207,37 @@ void ConfigImpl::refreshDdlHistory() if (ddlHistoryModel) ddlHistoryModel->refresh(); } + +QList > ConfigImpl::getScriptFunctions() +{ + QList > list; + SqlQueryPtr results = db->exec("SELECT * FROM script_functions"); + while (results->hasNext()) + { + SqlResultsRowPtr row = results->next(); + QHash fnHash = row->valueMap(); + fnHash["databases"] = QJsonDocument::fromJson(row->value("databases").toByteArray()).toVariant(); + fnHash["arguments"] = QJsonDocument::fromJson(row->value("arguments").toByteArray()).toVariant(); + list << fnHash; + } + return list; +} + +void ConfigImpl::setScriptFunctions(const QList >& newFunctions) +{ + db->begin(); + db->exec("DELETE FROM script_functions"); + for (const QHash& fnHash : newFunctions) + { + db->exec("INSERT INTO script_functions" + " (name, lang, code, \"initCode\", \"finalCode\", databases, arguments," + " \"type\", \"undefinedArgs\", \"allDatabases\", deterministic)" + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + {fnHash["name"].toString(), fnHash["lang"].toString(), + fnHash["code"].toString(), fnHash["initCode"].toString(), fnHash["finalCode"].toString(), + QString::fromUtf8(QJsonDocument(QJsonArray::fromVariantList(fnHash["databases"].toList())).toJson(QJsonDocument::Compact)), + QString::fromUtf8(QJsonDocument(QJsonArray::fromVariantList(fnHash["arguments"].toList())).toJson(QJsonDocument::Compact)), + fnHash["type"], fnHash["undefinedArgs"], fnHash["allDatabases"], fnHash["deterministic"]}); + } + db->commit(); +} diff --git a/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.h b/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.h index 9f0f36efca..94b32b7cd0 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.h +++ b/SQLiteStudio3/coreSQLiteStudio/services/impl/configimpl.h @@ -86,6 +86,9 @@ class API_EXPORT ConfigImpl : public Config void deleteReport(int id); void clearReportHistory(); + QList > getScriptFunctions(); + void setScriptFunctions(const QList >& newFunctions); + void begin(); void commit(); void rollback(); @@ -110,6 +113,7 @@ class API_EXPORT ConfigImpl : public Config void storeGroup(const DbGroupPtr& group, qint64 parentId = -1); void readGroupRecursively(DbGroupPtr group); QString getConfigPath(); + void dropTables(const QList& tables); void initTables(); void initDbFile(); QList getStdDbPaths(); diff --git a/SQLiteStudio3/coreSQLiteStudio/services/impl/functionmanagerimpl.cpp b/SQLiteStudio3/coreSQLiteStudio/services/impl/functionmanagerimpl.cpp index 1b49f3b00c..b24a4ba712 100644 --- a/SQLiteStudio3/coreSQLiteStudio/services/impl/functionmanagerimpl.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/services/impl/functionmanagerimpl.cpp @@ -338,8 +338,8 @@ void FunctionManagerImpl::refreshFunctionsByKey() void FunctionManagerImpl::storeInConfig() { - QVariantList list; - QHash fnHash; + QList > list; + QHash fnHash; for (ScriptFunction* func : functions) { fnHash["name"] = func->name; @@ -352,21 +352,21 @@ void FunctionManagerImpl::storeInConfig() fnHash["type"] = static_cast(func->type); fnHash["undefinedArgs"] = func->undefinedArgs; fnHash["allDatabases"] = func->allDatabases; + fnHash["deterministic"] = func->deterministic; list << fnHash; } - CFG_CORE.Internal.Functions.set(list); + CFG->setScriptFunctions(list); } void FunctionManagerImpl::loadFromConfig() { clearFunctions(); - QVariantList list = CFG_CORE.Internal.Functions.get(); - QHash fnHash; + QList > list = CFG->getScriptFunctions(); + QHash fnHash; ScriptFunction* func = nullptr; - for (const QVariant& var : list) + for (const QHash& fnHash : list) { - fnHash = var.toHash(); func = new ScriptFunction(); func->name = fnHash["name"].toString(); func->lang = updateScriptingQtLang(fnHash["lang"].toString()); @@ -378,6 +378,7 @@ void FunctionManagerImpl::loadFromConfig() func->type = static_cast(fnHash["type"].toInt()); func->undefinedArgs = fnHash["undefinedArgs"].toBool(); func->allDatabases = fnHash["allDatabases"].toBool(); + func->deterministic = fnHash["deterministic"].toBool(); functions << func; } }