diff --git a/autotests/KDbTestUtils.cpp b/autotests/KDbTestUtils.cpp index 51fcc5a8..47be9863 100644 --- a/autotests/KDbTestUtils.cpp +++ b/autotests/KDbTestUtils.cpp @@ -1,388 +1,410 @@ /* This file is part of the KDE project Copyright (C) 2015-2018 Jarosław Staniek This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KDbTestUtils.h" #include "KDbUtils_p.h" #include #include #include #include #include #include #include #include #include #include #include #include "../tests/features/tables_test_p.h" namespace QTest { KDBTESTUTILS_EXPORT bool qCompare(const KDbEscapedString &val1, const KDbEscapedString &val2, const char *actual, const char *expected, const char *file, int line) { return val1 == val2 ? compare_helper(true, "COMPARE()", toString(qPrintable(val1.toString())), toString(qPrintable(val2.toString())), actual, expected, file, line) : compare_helper(false, "Compared values are not the same", toString(qPrintable(val1.toString())), toString(qPrintable(val2.toString())), actual, expected, file, line); } KDBTESTUTILS_EXPORT bool qCompare(const KDbEscapedString &val1, const char *val2, const char *actual, const char *expected, const char *file, int line) { return val1 == val2 ? compare_helper(true, "COMPARE()", toString(qPrintable(val1.toString())), toString(val2), actual, expected, file, line) : compare_helper(false, "Compared values are not the same", toString(qPrintable(val1.toString())), toString(val2), actual, expected, file, line); } KDBTESTUTILS_EXPORT bool qCompare(const char *val1, const KDbEscapedString &val2, const char *actual, const char *expected, const char *file, int line) { return val1 == val2 ? compare_helper(true, "COMPARE()", toString(val1), toString(qPrintable(val2.toString())), actual, expected, file, line) : compare_helper(false, "Compared values are not the same", toString(val1), toString(qPrintable(val2.toString())), actual, expected, file, line); } KDBTESTUTILS_EXPORT bool qCompare(const KDbEscapedString &val1, const QString &val2, const char *actual, const char *expected, const char *file, int line) { return val1 == KDbEscapedString(val2) ? compare_helper(true, "COMPARE()", toString(qPrintable(val1.toString())), toString(val2), actual, expected, file, line) : compare_helper(false, "Compared values are not the same", toString(qPrintable(val1.toString())), toString(val2), actual, expected, file, line); } KDBTESTUTILS_EXPORT bool qCompare(const QString &val1, const KDbEscapedString &val2, const char *actual, const char *expected, const char *file, int line) { return KDbEscapedString(val1) == val2 ? compare_helper(true, "COMPARE()", toString(val1), toString(qPrintable(val2.toString())), actual, expected, file, line) : compare_helper(false, "Compared values are not the same", toString(val1), toString(qPrintable(val2.toString())), actual, expected, file, line); } + +static char *toString(const QStringList &list) +{ + return toString(qPrintable(QStringLiteral("QStringList(%1)").arg(list.join(", ")))); +} + +KDBTESTUTILS_EXPORT bool qCompare(const QStringList &val1, const QStringList &val2, + const char *actual, const char *expected, const char *file, + int line) +{ + return val1 == val2 ? compare_helper(true, "COMPARE()", toString(val1), toString(val2), actual, + expected, file, line) + : compare_helper(false, "Compared values are not the same", toString(val1), + toString(val2), actual, expected, file, line); +} } class KDbTestUtils::Private { public: Private() {} QScopedPointer kdbBuilder; QScopedPointer driverBuilder; KDbConnection *connection() { return m_connection.data(); } void setConnection(KDbConnection *conn) { kdbBuilder.reset(); // dependency will be removed m_connection.reset(conn); } KDbConnection* takeConnection() { if (!m_connection) { return nullptr; } kdbBuilder.reset(); // dependency may be removed return m_connection.take(); } private: QScopedPointer m_connection; }; KDbTestUtils::KDbTestUtils() : d(new Private) { QCoreApplication::addLibraryPath(KDB_LOCAL_PLUGINS_DIR); // make plugins work without installing them } KDbTestUtils::~KDbTestUtils() { delete d; } KDbConnection* KDbTestUtils::connection() { return d->connection(); } KDbNativeStatementBuilder* KDbTestUtils::kdbBuilder() { Q_ASSERT(connection()); if (connection() && !d->kdbBuilder) { d->kdbBuilder.reset(new KDbNativeStatementBuilder(connection(), KDb::KDbEscaping)); } return d->kdbBuilder.data(); } KDbNativeStatementBuilder* KDbTestUtils::driverBuilder() { Q_ASSERT(connection()); if (connection() && !d->driverBuilder) { d->driverBuilder.reset(new KDbNativeStatementBuilder(connection(), KDb::DriverEscaping)); } return d->driverBuilder.data(); } void KDbTestUtils::testDriverManagerInternal(bool forceEmpty) { DriverManagerInternal::self()->forceEmpty = forceEmpty; QStringList ids = manager.driverIds(); //qDebug() << "DRIVERS:" << ids; QVERIFY2(forceEmpty == manager.result().isError(), "Error in driver manager"); //qDebug() << manager.result().message(); QVERIFY2(forceEmpty == ids.isEmpty(), "No db drivers found"); if (forceEmpty) { // no drivers, so try to find one and expect failure ids << "org.kde.kdb.sqlite"; } for (const QString &id : qAsConst(ids)) { const KDbDriverMetaData* driverMetaData; if (forceEmpty) { KDB_EXPECT_FAIL(manager.resultable(), driverMetaData = manager.driverMetaData(id), ERR_DRIVERMANAGER, "Driver metadata not found"); // find driver for the metadata KDB_EXPECT_FAIL(manager.resultable(), driver = manager.driver(id), ERR_DRIVERMANAGER, "Driver not found"); } else { KDB_VERIFY(manager.resultable(), driverMetaData = manager.driverMetaData(id), "Driver metadata not found"); QCOMPARE(driverMetaData->id(), id); // find driver for the metadata KDB_VERIFY(manager.resultable(), driver = manager.driver(id), "Driver not found"); } } DriverManagerInternal::self()->forceEmpty = false; // default state } void KDbTestUtils::testDriverManagerInternal() { testDriverManagerInternal(true); testDriverManagerInternal(false); } -void KDbTestUtils::testDriver(const QString &driverId, bool fileBased, const QStringList &mimeTypes) +void KDbTestUtils::testDriver(const QString &driverId, bool fileBased, const QStringList &mimeTypes, + const QStringList &possiblyInvalidMimeTypes) { // find the metadata const KDbDriverMetaData* driverMetaData; KDB_VERIFY(manager.resultable(), driverMetaData = manager.driverMetaData(driverId), "Driver metadata not found"); QCOMPARE(driverMetaData->id(), driverId); QCOMPARE(driverMetaData->isFileBased(), fileBased); // test the mimetypes QStringList foundMimeTypes(driverMetaData->mimeTypes()); foundMimeTypes.sort(); QStringList expectedMimeTypes(mimeTypes); expectedMimeTypes.sort(); //qDebug() << "mimeTypes:" << mimeTypes; QCOMPARE(foundMimeTypes, expectedMimeTypes); QVERIFY(!KDb::defaultFileBasedDriverMimeType().isEmpty()); QMimeDatabase mimeDb; foreach(const QString &mimeName, expectedMimeTypes) { - QVERIFY2(mimeDb.mimeTypeForName(mimeName).isValid(), - qPrintable(QString("%1 MIME type not found in the MIME database").arg(mimeName))); + if (!mimeDb.mimeTypeForName(mimeName).isValid()) { + const QString msg = QStringLiteral("%1 MIME type not found in the MIME database").arg(mimeName); + if (possiblyInvalidMimeTypes.contains(mimeName)) { + qInfo() << qPrintable(msg); + } else { + QVERIFY2(mimeDb.mimeTypeForName(mimeName).isValid(), qPrintable(msg)); + } + } } // find driver for the metadata KDB_VERIFY(manager.resultable(), driver = manager.driver(driverId), "Driver not found"); } void KDbTestUtils::testSqliteDriverInternal() { - QStringList mimeTypes; - mimeTypes << "application/x-kexiproject-sqlite3" << "application/x-sqlite3"; - testDriver("org.kde.kdb.sqlite", - true, // file-based - mimeTypes); - QVERIFY2(mimeTypes.contains(KDb::defaultFileBasedDriverMimeType()), "SQLite's MIME types should include the default file based one"); + const QStringList mimeTypes { "application/x-kexiproject-sqlite3", "application/x-sqlite3", + "application/x-vnd.kde.kexi", "application/vnd.sqlite3" }; + const QStringList possiblyInvalidMimeTypes { "application/vnd.sqlite3" }; + testDriver("org.kde.kdb.sqlite", true /* file-based */, mimeTypes, possiblyInvalidMimeTypes); + QVERIFY2(mimeTypes.contains(KDb::defaultFileBasedDriverMimeType()), + "SQLite's MIME types should include the default file based one"); } void KDbTestUtils::testConnectInternal(const KDbConnectionData &cdata, const KDbConnectionOptions &options) { //qDebug() << cdata; if (!driver) { //! @todo don't hardcode SQLite here KDB_VERIFY(manager.resultable(), driver = manager.driver("org.kde.kdb.sqlite"), "Driver not found"); } KDbConnectionOptions connOptionsOverride(options); QStringList extraSqliteExtensionPaths; extraSqliteExtensionPaths << SQLITE_LOCAL_ICU_EXTENSION_PATH; connOptionsOverride.insert("extraSqliteExtensionPaths", extraSqliteExtensionPaths); d->setConnection(nullptr); // remove previous connection if present const int connCount = driver->connections().count(); d->setConnection(driver->createConnection(cdata, connOptionsOverride)); KDB_VERIFY(driver, connection(), "Failed to create connection"); QVERIFY2(cdata.driverId().isEmpty(), "Connection data has filled driver ID"); QCOMPARE(connection()->data().driverId(), driver->metaData()->id()); QVERIFY2(driver->connections().contains(connection()), "Driver does not list created connection"); QCOMPARE(driver->connections().count(), connCount + 1); // one more const KDbUtils::Property extraSqliteExtensionPathsProperty = connection()->options()->property("extraSqliteExtensionPaths"); QVERIFY2(!extraSqliteExtensionPathsProperty.isNull(), "extraSqliteExtensionPaths property not found"); QCOMPARE(extraSqliteExtensionPathsProperty.value().type(), QVariant::StringList); QCOMPARE(extraSqliteExtensionPathsProperty.value().toStringList(), extraSqliteExtensionPaths); const KDbUtils::Property readOnlyProperty = connection()->options()->property("readOnly"); QVERIFY2(!readOnlyProperty.isNull(), "readOnly property not found"); QCOMPARE(readOnlyProperty.value().toBool(), connection()->options()->isReadOnly()); //! @todo Add extensive test for a read-only connection KDB_VERIFY(connection(), connection()->connect(), "Failed to connect"); KDB_VERIFY(connection(), connection()->isConnected(), "Database not connected after call to connect()"); } void KDbTestUtils::testUseInternal() { KDB_VERIFY(connection(), connection()->databaseExists(connection()->data().databaseName()), "Database does not exist"); KDB_VERIFY(connection(), connection()->useDatabase(), "Failed to use database"); KDB_VERIFY(connection(), connection()->isDatabaseUsed(), "Database not used after call to useDatabase()"); } void KDbTestUtils::testConnectAndUseInternal(const KDbConnectionData &cdata, const KDbConnectionOptions &options) { if (!testConnect(cdata, options) || !connection()) { qWarning() << driver->result(); QFAIL("testConnect"); } if (!testUse() || !connection()->isDatabaseUsed()) { qWarning() << connection()->result(); bool result = testDisconnect(); Q_UNUSED(result); QFAIL("testUse"); } } void KDbTestUtils::testConnectAndUseInternal(const QString &path, const KDbConnectionOptions &options) { KDbConnectionData cdata; cdata.setDatabaseName(path); testConnectAndUseInternal(cdata, options); } void KDbTestUtils::testCreateDbInternal(const QString &dbName) { //open connection KDbConnectionData cdata; //! @todo don't hardcode SQLite (.kexi) extension here QString fullDbName(QDir::fromNativeSeparators(QFile::decodeName(FILES_OUTPUT_DIR "/") + dbName + ".kexi")); cdata.setDatabaseName(fullDbName); QVERIFY(testConnect(cdata)); QVERIFY(connection()); //! @todo KDbDriver::metaData { QScopedPointer connGuard(d->takeConnection()); if (connGuard->databaseExists(dbName)) { KDB_VERIFY(connGuard, connGuard->dropDatabase(fullDbName), "Failed to drop database"); } KDB_VERIFY(connGuard, !connGuard->databaseExists(fullDbName), "Database exists"); KDB_VERIFY(connGuard, connGuard->createDatabase(fullDbName), "Failed to create db"); KDB_VERIFY(connGuard, connGuard->databaseExists(fullDbName), "Database does not exist after creation"); d->setConnection(connGuard.take()); } } void KDbTestUtils::testCreateDbWithTablesInternal(const QString &dbName) { QVERIFY(testCreateDb(dbName)); KDB_VERIFY(connection(), connection()->useDatabase(), "Failed to use database"); testCreateTablesInternal(); } void KDbTestUtils::testPropertiesInternal() { QStringList properties; properties << connection()->databaseProperties().names(); QVERIFY(properties.contains("kexidb_major_ver")); bool ok; QVERIFY(connection()->databaseProperties().value("kexidb_major_ver").toInt(&ok) >= 0); QVERIFY(ok); QVERIFY(properties.contains("kexidb_minor_ver")); QVERIFY(connection()->databaseProperties().value("kexidb_minor_ver").toInt(&ok) >= 0); QVERIFY(ok); } void KDbTestUtils::testCreateTablesInternal() { QVERIFY2(tablesTest_createTables(connection()) == 0, "Failed to create test data"); } void KDbTestUtils::testDisconnectPrivate() { if (!connection()) { return; } KDB_VERIFY(connection(), connection()->closeDatabase(), "Failed to close database"); KDB_VERIFY(connection(), !connection()->isDatabaseUsed(), "Database still used after closing"); KDB_VERIFY(connection(), connection()->closeDatabase(), "Second closeDatabase() call should not fail"); KDB_VERIFY(connection(), connection()->disconnect(), "Failed to disconnect database"); KDB_VERIFY(connection(), !connection()->isConnected(), "Database still connected after disconnecting"); KDB_VERIFY(connection(), connection()->disconnect(), "Second disconnect() call should not fail"); } void KDbTestUtils::testDisconnectInternal() { const int connCount = driver ? driver->connections().count() : 0; testDisconnectPrivate(); QVERIFY(!QTest::currentTestFailed()); d->setConnection(nullptr); QCOMPARE(driver ? driver->connections().count() : -1, connCount - 1); // one less } void KDbTestUtils::testDropDbInternal() { QVERIFY(connection()->dropDatabase(connection()->data().databaseName())); } void KDbTestUtils::testDisconnectAndDropDbInternal() { QString dbName(connection()->data().databaseName()); testDisconnectPrivate(); QVERIFY(!QTest::currentTestFailed()); KDB_VERIFY(connection(), connection()->dropDatabase(dbName), "Failed to drop database"); d->setConnection(nullptr); } diff --git a/autotests/KDbTestUtils.h b/autotests/KDbTestUtils.h index 0ac0b7cb..d007df8c 100644 --- a/autotests/KDbTestUtils.h +++ b/autotests/KDbTestUtils.h @@ -1,203 +1,208 @@ /* This file is part of the KDE project Copyright (C) 2015-2018 Jarosław Staniek This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KDB_TESTUTILS_H #define KDB_TESTUTILS_H #include "kdbtestutils_export.h" #include #include #include #include #include #include class KDbNativeStatementBuilder; Q_DECLARE_METATYPE(KDbField::TypeGroup) Q_DECLARE_METATYPE(KDbField::Type) Q_DECLARE_METATYPE(KDb::Signedness) Q_DECLARE_METATYPE(QList) Q_DECLARE_METATYPE(KDb::BLOBEscapingType) //! @internal for KDB_VERIFY template const T* KDB_POINTER_WRAPPER(const T &t) { return &t; } //! @internal for KDB_VERIFY template const T* KDB_POINTER_WRAPPER(const T *t) { return t; } //! @internal for KDB_VERIFY template T* KDB_POINTER_WRAPPER(T *t) { return t; } //! @internal for KDB_VERIFY template T* KDB_POINTER_WRAPPER(const QPointer &t) { return t.data(); } //! @internal for KDB_VERIFY template T* KDB_POINTER_WRAPPER(const QScopedPointer &t) { return t.data(); } namespace QTest { KDBTESTUTILS_EXPORT bool qCompare(const KDbEscapedString &val1, const KDbEscapedString &val2, const char *actual, const char *expected, const char *file, int line); KDBTESTUTILS_EXPORT bool qCompare(const KDbEscapedString &val1, const char *val2, const char *actual, const char *expected, const char *file, int line); KDBTESTUTILS_EXPORT bool qCompare(const char *val1, const KDbEscapedString &val2, const char *actual, const char *expected, const char *file, int line); KDBTESTUTILS_EXPORT bool qCompare(const KDbEscapedString &val1, const QString &val2, const char *actual, const char *expected, const char *file, int line); KDBTESTUTILS_EXPORT bool qCompare(const QString &val1, const KDbEscapedString &val2, const char *actual, const char *expected, const char *file, int line); + +KDBTESTUTILS_EXPORT bool qCompare(const QStringList &val1, const QStringList &val2, + const char *actual, const char *expected, const char *file, + int line); } //! Calls @a call and verifies status of @a resultable //! On error displays the status on debug and does the same as QVERIFY with @a errorMessage #define KDB_VERIFY(resultable, call, errorMessage) \ do { \ bool KDB_VERIFY_ok = (call); \ const KDbResultable *KDB_VERIFY_resultablePtr = KDB_POINTER_WRAPPER(resultable); \ if (KDB_VERIFY_resultablePtr->result().isError()) { \ qDebug() << KDB_VERIFY_resultablePtr->result(); \ } \ if (!QTest::qVerify(KDB_VERIFY_ok && !KDB_VERIFY_resultablePtr->result().isError(), # call, (errorMessage), __FILE__, __LINE__)) {\ return; \ } \ } \ while (false) //! Calls @a call and verifies status of @a resultable //! On error displays the status on debug and does the same as QVERIFY with @a errorMessage #define KDB_EXPECT_FAIL(resultable, call, expectedErrorCode, errorMessage) \ do { \ bool KDB_VERIFY_ok = (call); \ const KDbResultable *KDB_VERIFY_resultablePtr = KDB_POINTER_WRAPPER(resultable); \ if (KDB_VERIFY_resultablePtr->result().isError()) { \ qDebug() << KDB_VERIFY_resultablePtr->result(); \ } \ QVERIFY(KDB_VERIFY_resultablePtr->result().isError()); \ if (!QTest::qVerify(!KDB_VERIFY_ok, # call, (errorMessage), __FILE__, __LINE__)) {\ return; \ } \ if (!QTest::qCompare(KDB_VERIFY_resultablePtr->result().code(), expectedErrorCode, # call, # expectedErrorCode, __FILE__, __LINE__)) {\ return; \ } \ } \ while (false) //! Declares method @a name that returns false on test failure, it can be called as utility function. //! Also declared internal method name ## Internal which performs the actual test. //! This way users of this method can call QVERIFY(utils.()); #define KDBTEST_METHOD_DECL(name, argsDecl, args) \ public: \ bool name argsDecl Q_REQUIRED_RESULT { name ## Internal args ; return !QTest::currentTestFailed(); } \ private Q_SLOTS: \ void name ## Internal argsDecl //! Test utilities that provide basic database features class KDBTESTUTILS_EXPORT KDbTestUtils : public QObject { Q_OBJECT public: KDbTestUtils(); ~KDbTestUtils(); KDbDriverManager manager; QPointer driver; /** * Returns associated connection */ KDbConnection* connection(); /** * Returns builder for generating KDb SQL statements */ KDbNativeStatementBuilder* kdbBuilder(); /** * Returns builder for generating driver-native SQL statements */ KDbNativeStatementBuilder* driverBuilder(); KDBTEST_METHOD_DECL(testDriverManager, (), ()); KDBTEST_METHOD_DECL(testSqliteDriver, (), ()); //! Connects to a database //! @since 3.2 KDBTEST_METHOD_DECL(testConnect, (const KDbConnectionData &cdata, const KDbConnectionOptions &options = KDbConnectionOptions()), (cdata, options)); KDBTEST_METHOD_DECL(testUse, (), ()); //! Convenience method that performs testConnect and testUse in one go //! @since 3.2 KDBTEST_METHOD_DECL(testConnectAndUse, (const KDbConnectionData &cdata, const KDbConnectionOptions &options = KDbConnectionOptions()), (cdata, options)); //! Overload of testConnectAndUse for file-based databases //! @since 3.2 KDBTEST_METHOD_DECL(testConnectAndUse, (const QString &path, const KDbConnectionOptions &options = KDbConnectionOptions()), (path, options)); //! Creates database with name @a dbName //! Does not use the database. //! @todo don't hardcode SQLite here //! @note dbName should not include ".kexi" extension or path KDBTEST_METHOD_DECL(testCreateDb, (const QString &dbName), (dbName)); //! Creates database with name @a dbName, then uses it and creates test tables //! The database stays used. //! @note dbName should not include ".kexi" extension or path KDBTEST_METHOD_DECL(testCreateDbWithTables, (const QString &dbName), (dbName)); KDBTEST_METHOD_DECL(testProperties, (), ()); KDBTEST_METHOD_DECL(testCreateTables, (), ()); KDBTEST_METHOD_DECL(testDisconnect, (), ()); KDBTEST_METHOD_DECL(testDropDb, (), ()); KDBTEST_METHOD_DECL(testDisconnectAndDropDb, (), ()); protected: void testDisconnectPrivate(); - void testDriver(const QString &driverId, bool fileBased, const QStringList &mimeTypes); + void testDriver(const QString &driverId, bool fileBased, const QStringList &mimeTypes, + const QStringList &possiblyInvalidMimeTypes); void testDriverManagerInternal(bool forceEmpty); private: Q_DISABLE_COPY(KDbTestUtils) class Private; Private * const d; }; #endif diff --git a/src/drivers/sqlite/kdb_sqlitedriver.json b/src/drivers/sqlite/kdb_sqlitedriver.json index a7fbc72d..154d8e6c 100644 --- a/src/drivers/sqlite/kdb_sqlitedriver.json +++ b/src/drivers/sqlite/kdb_sqlitedriver.json @@ -1,103 +1,105 @@ { "KPlugin": { "Authors": [ { "Email": "kexi@kde.org", "Name": "Kexi Team", "Name[ast]": "L'equipu Kexi", "Name[ca@valencia]": "L'equip del Kexi", "Name[ca]": "L'equip del Kexi", "Name[cs]": "Tým Kexi", "Name[de]": "Kexi-Team", "Name[en_GB]": "Kexi Team", "Name[es]": "El equipo de Kexi", "Name[fi]": "Kexi-työryhmä", "Name[fr]": "L'équipe Kexi", "Name[gl]": "Equipo de Kexi", "Name[ia]": "Equipa de Kexi", "Name[it]": "La squadra di Kexi", "Name[nl]": "Het team van Kexi", "Name[nn]": "Kexi-gruppa", "Name[pl]": "Zespół Kexi", "Name[pt]": "Equipa do Kexi", "Name[pt_BR]": "Equipe do Kexi", "Name[ru]": "Команда разработчиков Kexi", "Name[sk]": "Tím Kexi", "Name[sv]": "Kexi-gruppen", "Name[tr]": "Kexi Ekibi", "Name[uk]": "Команда Kexi", "Name[x-test]": "xxKexi Teamxx", "Name[zh_CN]": "Kexi 团队", "Name[zh_TW]": "Kexi 團隊" } ], "Category": "", "Dependencies": [], "Description": "KDb driver for handling SQLite databases", "Description[ast]": "Controladora KDb pa remanar bases de datos SQLite", "Description[ca@valencia]": "Controlador del KDb per a gestionar bases de dades SQLite", "Description[ca]": "Controlador del KDb per a gestionar bases de dades SQLite", "Description[cs]": "Ovladač KDb pro práci s databázemi SQLite", "Description[de]": "KDb-Treiber für SQLite", "Description[en_GB]": "KDb driver for handling SQLite databases", "Description[es]": "Controlador de KDb para manejar bases de datos SQLite", "Description[fi]": "KDb-ajuri SQLite-tietokantojen käsittelyyn", "Description[fr]": "Pilote KDb de gestion des bases de données SQLite", "Description[gl]": "Controlador de KDb para manexar bases de datos SQLite.", "Description[ia]": "Driver de KDb per manear bases de datos deSQLite", "Description[it]": "Driver KDb per la gestione di banche dati SQLite", "Description[nl]": "KDb-stuurprogramma for behandeling van SQLite databases", "Description[nn]": "KDb-drivar for SQLite-databasar", "Description[pl]": "Sterownik KDb do obsługi baz danych SQLite", "Description[pt]": "Controlador do KDb para lidar com bases de dados SQLite", "Description[pt_BR]": "Driver do KDb para lidar com bancos de dados SQLite", "Description[sk]": "KDb ovládač na spracovanie databáz SQLite", "Description[sv]": "Kdb-drivrutin för att hantera SQLite-databaser", "Description[tr]": "SQLite veritabanlarını kullanabilmek için KDb sürücüsü", "Description[uk]": "Драйвер KDb для роботи з базами даних SQLite", "Description[x-test]": "xxKDb driver for handling SQLite databasesxx", "Description[zh_CN]": "处理 SQLite 数据库的 KDb 驱动", "Description[zh_TW]": "處理 SQLite 資料庫的 KDb 驅動", "EnabledByDefault": true, "Icon": "", "Id": "org.kde.kdb.sqlite", "License": "LGPL", "MimeTypes": [ "application/x-kexiproject-sqlite3", - "application/x-sqlite3" + "application/x-sqlite3", + "application/x-vnd.kde.kexi", + "application/vnd.sqlite3" ], "Name": "SQLite", "Name[ast]": "SQLite", "Name[ca@valencia]": "SQLite", "Name[ca]": "SQLite", "Name[cs]": "SQLite", "Name[de]": "SQLite", "Name[en_GB]": "SQLite", "Name[es]": "SQLite", "Name[fi]": "SQLite", "Name[fr]": "SQLite", "Name[gl]": "SQLite", "Name[ia]": "SQLite", "Name[it]": "SQLite", "Name[nl]": "SQLite", "Name[nn]": "SQLite", "Name[pl]": "SQLite", "Name[pt]": "SQLite", "Name[pt_BR]": "SQLite", "Name[ru]": "SQLite", "Name[sk]": "SQLite", "Name[sv]": "SQLite", "Name[tr]": "SQLite", "Name[uk]": "SQLite", "Name[x-test]": "xxSQLitexx", "Name[zh_CN]": "SQLite", "Name[zh_TW]": "SQLite", "ServiceTypes": [ "KDb/Driver" ], "Version": "3.2", "Website": "https://kexi-project.org" }, "X-KDb-FileBased": "true", "X-KDb-ImportingEnabled": "false" }