Browse Source

[sqflite] Refactor codebase

merge-requests/10/head
Denis Glazkov 2 years ago committed by Vitaliy Zarubin
parent
commit
d91bee193d
  1. 5
      packages/sqflite/sqflite_aurora/aurora/CMakeLists.txt
  2. 10
      packages/sqflite/sqflite_aurora/aurora/include/sqflite_aurora/async_queue.h
  3. 96
      packages/sqflite/sqflite_aurora/aurora/include/sqflite_aurora/constants.h
  4. 89
      packages/sqflite/sqflite_aurora/aurora/include/sqflite_aurora/database.h
  5. 10
      packages/sqflite/sqflite_aurora/aurora/include/sqflite_aurora/globals.h
  6. 21
      packages/sqflite/sqflite_aurora/aurora/include/sqflite_aurora/logger.h
  7. 27
      packages/sqflite/sqflite_aurora/aurora/include/sqflite_aurora/sqflite_aurora_plugin.h
  8. 30
      packages/sqflite/sqflite_aurora/aurora/include/sqflite_aurora/utils.h
  9. 6
      packages/sqflite/sqflite_aurora/aurora/lib/async_queue.cpp
  10. 280
      packages/sqflite/sqflite_aurora/aurora/lib/database.cpp
  11. 34
      packages/sqflite/sqflite_aurora/aurora/lib/logger.cpp
  12. 370
      packages/sqflite/sqflite_aurora/aurora/lib/sqflite_aurora_plugin.cpp
  13. 28
      packages/sqflite/sqflite_aurora/aurora/lib/utils.cpp

5
packages/sqflite/sqflite_aurora/aurora/CMakeLists.txt

@ -19,10 +19,11 @@ pkg_check_modules(FlutterEmbedder REQUIRED IMPORTED_TARGET flutter-embedder)
pkg_check_modules(SQLite REQUIRED IMPORTED_TARGET sqlite3) pkg_check_modules(SQLite REQUIRED IMPORTED_TARGET sqlite3)
add_library(${PLUGIN_NAME} SHARED add_library(${PLUGIN_NAME} SHARED
lib/asynq.cpp lib/async_queue.cpp
lib/database.cpp lib/database.cpp
lib/logger.cpp lib/logger.cpp
lib/sqflite_aurora_plugin.cpp) lib/sqflite_aurora_plugin.cpp
lib/utils.cpp)
set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) set_target_properties(${PLUGIN_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden)
target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::FlutterEmbedder PkgConfig::SQLite) target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::FlutterEmbedder PkgConfig::SQLite)

10
packages/sqflite/sqflite_aurora/aurora/include/sqflite_aurora/asynq.h → packages/sqflite/sqflite_aurora/aurora/include/sqflite_aurora/async_queue.h

@ -8,14 +8,10 @@
#include <condition_variable> #include <condition_variable>
#include <functional> #include <functional>
#include <mutex> #include <mutex>
#include <thread>
#include <queue> #include <queue>
#include <thread>
#ifdef PLUGIN_IMPL #include <sqflite_aurora/globals.h>
#define PLUGIN_EXPORT __attribute__((visibility("default")))
#else
#define PLUGIN_EXPORT
#endif
class PLUGIN_EXPORT AsyncQueue final class PLUGIN_EXPORT AsyncQueue final
{ {
@ -26,7 +22,7 @@ public:
AsyncQueue(); AsyncQueue();
~AsyncQueue(); ~AsyncQueue();
void Push(const Task &task); void push(const Task &task);
private: private:
void run(); void run();

96
packages/sqflite/sqflite_aurora/aurora/include/sqflite_aurora/constants.h

@ -7,55 +7,55 @@
#include <string> #include <string>
const std::string METHOD_GET_PLATFORM_VERSION = "getPlatformVersion"; const inline std::string METHOD_GET_PLATFORM_VERSION = "getPlatformVersion";
const std::string METHOD_GET_DATABASES_PATH = "getDatabasesPath"; const inline std::string METHOD_GET_DATABASES_PATH = "getDatabasesPath";
const std::string METHOD_DEBUG = "debug"; const inline std::string METHOD_DEBUG = "debug";
const std::string METHOD_OPTIONS = "options"; const inline std::string METHOD_OPTIONS = "options";
const std::string METHOD_OPEN_DATABASE = "openDatabase"; const inline std::string METHOD_OPEN_DATABASE = "openDatabase";
const std::string METHOD_CLOSE_DATABASE = "closeDatabase"; const inline std::string METHOD_CLOSE_DATABASE = "closeDatabase";
const std::string METHOD_INSERT = "insert"; const inline std::string METHOD_INSERT = "insert";
const std::string METHOD_EXECUTE = "execute"; const inline std::string METHOD_EXECUTE = "execute";
const std::string METHOD_QUERY = "query"; const inline std::string METHOD_QUERY = "query";
const std::string METHOD_QUERY_CURSOR_NEXT = "queryCursorNext"; const inline std::string METHOD_QUERY_CURSOR_NEXT = "queryCursorNext";
const std::string METHOD_UPDATE = "update"; const inline std::string METHOD_UPDATE = "update";
const std::string METHOD_BATCH = "batch"; const inline std::string METHOD_BATCH = "batch";
const std::string METHOD_DELETE_DATABASE = "deleteDatabase"; const inline std::string METHOD_DELETE_DATABASE = "deleteDatabase";
const std::string METHOD_DATABASE_EXISTS = "databaseExists"; const inline std::string METHOD_DATABASE_EXISTS = "databaseExists";
const std::string ARG_ID = "id"; const inline std::string ARG_ID = "id";
const std::string ARG_PATH = "path"; const inline std::string ARG_PATH = "path";
const std::string ARG_READ_ONLY = "readOnly"; const inline std::string ARG_READ_ONLY = "readOnly";
const std::string ARG_SINGLE_INSTANCE = "singleInstance"; const inline std::string ARG_SINGLE_INSTANCE = "singleInstance";
const std::string ARG_LOG_LEVEL = "logLevel"; const inline std::string ARG_LOG_LEVEL = "logLevel";
const std::string ARG_TRANSACTION_ID = "transactionId"; const inline std::string ARG_TRANSACTION_ID = "transactionId";
const std::string ARG_IN_TRANSACTION = "inTransaction"; const inline std::string ARG_IN_TRANSACTION = "inTransaction";
const std::string ARG_RECOVERED = "recovered"; const inline std::string ARG_RECOVERED = "recovered";
const std::string ARG_RECOVERED_IN_TRANSACTION = "recoveredInTransaction"; const inline std::string ARG_RECOVERED_IN_TRANSACTION = "recoveredInTransaction";
const std::string ARG_SQL = "sql"; const inline std::string ARG_SQL = "sql";
const std::string ARG_SQL_ARGUMENTS = "arguments"; const inline std::string ARG_SQL_ARGUMENTS = "arguments";
const std::string ARG_NO_RESULT = "noResult"; const inline std::string ARG_NO_RESULT = "noResult";
const std::string ARG_CONTINUE_ON_ERROR = "continueOnError"; const inline std::string ARG_CONTINUE_ON_ERROR = "continueOnError";
const std::string ARG_COLUMNS = "columns"; const inline std::string ARG_COLUMNS = "columns";
const std::string ARG_ROWS = "rows"; const inline std::string ARG_ROWS = "rows";
const std::string ARG_DATABASES = "databases"; const inline std::string ARG_DATABASES = "databases";
const std::string ARG_COMMAND = "cmd"; const inline std::string ARG_COMMAND = "cmd";
const std::string ARG_OPERATIONS = "operations"; const inline std::string ARG_OPERATIONS = "operations";
const std::string ARG_METHOD = "method"; const inline std::string ARG_METHOD = "method";
const std::string ARG_RESULT = "result"; const inline std::string ARG_RESULT = "result";
const std::string ARG_ERROR = "error"; const inline std::string ARG_ERROR = "error";
const std::string ARG_ERROR_CODE = "code"; const inline std::string ARG_ERROR_CODE = "code";
const std::string ARG_ERROR_MESSAGE = "message"; const inline std::string ARG_ERROR_MESSAGE = "message";
const std::string ARG_ERROR_DATA = "data"; const inline std::string ARG_ERROR_DATA = "data";
const std::string ARG_CURSOR_PAGE_SIZE = "cursorPageSize"; const inline std::string ARG_CURSOR_PAGE_SIZE = "cursorPageSize";
const std::string ARG_CURSOR_ID = "cursorId"; const inline std::string ARG_CURSOR_ID = "cursorId";
const std::string ARG_CANCEL = "cancel"; const inline std::string ARG_CANCEL = "cancel";
const std::string ERROR_SQFLITE = "sqlite_error"; const inline std::string ERROR_SQFLITE = "sqlite_error";
const std::string ERROR_OPEN = "open_failed"; const inline std::string ERROR_OPEN = "open_failed";
const std::string ERROR_CLOSE = "close_failed"; const inline std::string ERROR_CLOSE = "close_failed";
const std::string ERROR_CLOSED = "database_closed"; const inline std::string ERROR_CLOSED = "database_closed";
const std::string ERROR_BAD_PARAM = "bad_param"; const inline std::string ERROR_BAD_PARAM = "bad_param";
const std::string ERROR_BAD_ARGS = "bad_arguments"; const inline std::string ERROR_BAD_ARGS = "bad_arguments";
const std::string ERROR_INTERNAL = "internal"; const inline std::string ERROR_INTERNAL = "internal";
#endif /* FLUTTER_PLUGIN_SQFLITE_CONSTANTS_H */ #endif /* FLUTTER_PLUGIN_SQFLITE_CONSTANTS_H */

89
packages/sqflite/sqflite_aurora/aurora/include/sqflite_aurora/database.h

@ -8,21 +8,16 @@
#include <flutter/encodable.h> #include <flutter/encodable.h>
#include <flutter/method-call.h> #include <flutter/method-call.h>
#include <sqflite_aurora/globals.h>
#include <sqflite_aurora/logger.h> #include <sqflite_aurora/logger.h>
#include <sqflite_aurora/utils.h>
#include <functional> #include <functional>
#include <optional>
#include <sqlite3.h> #include <sqlite3.h>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <queue> #include <queue>
#ifdef PLUGIN_IMPL
#define PLUGIN_EXPORT __attribute__((visibility("default")))
#else
#define PLUGIN_EXPORT
#endif
class PLUGIN_EXPORT Database final class PLUGIN_EXPORT Database final
{ {
public: public:
@ -46,70 +41,64 @@ public:
}; };
public: public:
Database(int id, const std::string &path, bool singleton, const Logger &logger); Database(int id, const std::string &path, bool singleInstance, const Logger &logger);
~Database(); ~Database();
public: public:
std::optional<std::string> Open(); utils::error open();
std::optional<std::string> OpenReadOnly(); utils::error openReadOnly();
std::optional<std::string> Close(); utils::error close();
std::optional<std::string> Execute(const std::string &sql, const Encodable::List &args); utils::error execute(const std::string &sql, const Encodable::List &args);
std::optional<std::string> QueryCursorNext(int cursorID, bool cancel, Encodable::Map &result); utils::error queryCursorNext(int cursorID, bool cancel, Encodable::Map &result);
std::optional<std::string> Query(const std::string &sql, utils::error query(const std::string &sql, const Encodable::List &args, Encodable::Map &result);
const Encodable::List &args, utils::error queryWithPageSize(const std::string &sql,
Encodable::Map &result);
std::optional<std::string> QueryWithPageSize(const std::string &sql,
const Encodable::List &args, const Encodable::List &args,
int64_t pageSize, int64_t pageSize,
Encodable::Map &result); Encodable::Map &result);
std::optional<std::string> Insert(const std::string &sql, utils::error insert(const std::string &sql, const Encodable::List &args, int &insertID);
const Encodable::List &args, utils::error update(const std::string &sql, const Encodable::List &args, int &updated);
int &insertID); utils::error batch(const std::vector<Operation> &operations,
std::optional<std::string> Update(const std::string &sql,
const Encodable::List &args,
int &updated);
std::optional<std::string> Batch(const std::vector<Operation> &operations,
bool continueOnError, bool continueOnError,
Encodable::List &results); Encodable::List &results);
void EnterInTransaction(); void enterInTransaction();
void LeaveTransaction(); void leaveTransaction();
int CurrentTransactionID(); int currentTransactionID();
typedef std::function<void()> SqlCommandCallback; typedef std::function<void()> SqlCommandCallback;
void ProcessSqlCommand(int transactionID, const SqlCommandCallback &callback); void processSqlCommand(int transactionID, const SqlCommandCallback &callback);
public: public:
bool IsOpen() const; bool isOpen() const;
bool IsSingleInstance() const; bool isSingleInstance() const;
bool IsInTransaction() const; bool isInTransaction() const;
bool IsInMemory() const; bool isInMemory() const;
bool IsReadOnly() const; bool isReadOnly() const;
const std::string &Path() const; const std::string &path() const;
int64_t ID() const; int64_t id() const;
Logger::Level LogLevel() const; Logger::Level logLevel() const;
private: private:
std::string currentErrorMessage(); std::string currentErrorMessage();
std::optional<std::string> createParentDir(); utils::error createParentDir();
std::optional<std::string> bindStmtArgs(sqlite3_stmt *stmt, const Encodable::List &args); utils::error bindStmtArgs(sqlite3_stmt *stmt, const Encodable::List &args);
void closeCursor(const Cursor &cursor); void closeCursor(const Cursor &cursor);
std::optional<std::string> resultFromCursor(const Cursor &cursor, Encodable::Map &result); utils::error resultFromCursor(const Cursor &cursor, Encodable::Map &result);
private: private:
int64_t id; int64_t m_id;
std::string path; std::string m_path;
bool isSingleInstance; bool m_isSingleInstance;
bool isReadOnly; bool m_isReadOnly;
Logger logger; Logger m_logger;
int transactionID; int m_transactionID;
int currentTransactionID; int m_currentTransactionID;
std::queue<SqlCommandCallback> pendingSqlCallbacks; std::queue<SqlCommandCallback> m_pendingSqlCallbacks;
int64_t cursorID; int64_t m_cursorID;
std::unordered_map<int64_t, Cursor> cursors; std::unordered_map<int64_t, Cursor> m_cursors;
sqlite3 *db; sqlite3 *m_db;
}; };
#endif /* FLUTTER_PLUGIN_SQFLITE_DATABASE_H */ #endif /* FLUTTER_PLUGIN_SQFLITE_DATABASE_H */

10
packages/sqflite/sqflite_aurora/aurora/include/sqflite_aurora/globals.h

@ -0,0 +1,10 @@
#ifndef FLUTTER_PLUGIN_SQFLITE_GLOBALS_H
#define FLUTTER_PLUGIN_SQFLITE_GLOBALS_H
#ifdef PLUGIN_IMPL
#define PLUGIN_EXPORT __attribute__((visibility("default")))
#else
#define PLUGIN_EXPORT
#endif
#endif /* FLUTTER_PLUGIN_SQFLITE_GLOBALS_H */

21
packages/sqflite/sqflite_aurora/aurora/include/sqflite_aurora/logger.h

@ -6,14 +6,9 @@
#define FLUTTER_PLUGIN_SQFLITE_LOGGER_H #define FLUTTER_PLUGIN_SQFLITE_LOGGER_H
#include <flutter/logger.h> #include <flutter/logger.h>
#include <sqflite_aurora/globals.h>
#include <string> #include <string>
#ifdef PLUGIN_IMPL
#define PLUGIN_EXPORT __attribute__((visibility("default")))
#else
#define PLUGIN_EXPORT
#endif
class PLUGIN_EXPORT Logger final class PLUGIN_EXPORT Logger final
{ {
public: public:
@ -26,19 +21,19 @@ public:
public: public:
Logger(Level level, const std::string &tag); Logger(Level level, const std::string &tag);
Level LogLevel() const; Level logLevel() const;
void SetLogLevel(Level level); void setLogLevel(Level level);
std::string Tag() const; std::string tag() const;
void SetTag(const std::string &tag); void setTag(const std::string &tag);
std::ostream &verb(); std::ostream &verb();
std::ostream &sql(); std::ostream &sql();
private: private:
Level level; Level m_level;
std::string tag; std::string m_tag;
std::ostream devnull; std::ostream m_devnull;
}; };
#endif /* FLUTTER_PLUGIN_SQFLITE_LOGGER_H */ #endif /* FLUTTER_PLUGIN_SQFLITE_LOGGER_H */

27
packages/sqflite/sqflite_aurora/aurora/include/sqflite_aurora/sqflite_aurora_plugin.h

@ -7,19 +7,14 @@
#include <flutter/plugin-interface.h> #include <flutter/plugin-interface.h>
#include <sqflite_aurora/asynq.h> #include <sqflite_aurora/async_queue.h>
#include <sqflite_aurora/database.h> #include <sqflite_aurora/database.h>
#include <sqflite_aurora/globals.h>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <unordered_map> #include <unordered_map>
#ifdef PLUGIN_IMPL
#define PLUGIN_EXPORT __attribute__((visibility("default")))
#else
#define PLUGIN_EXPORT
#endif
class PLUGIN_EXPORT SqfliteAuroraPlugin final : public PluginInterface class PLUGIN_EXPORT SqfliteAuroraPlugin final : public PluginInterface
{ {
public: public:
@ -49,8 +44,8 @@ private:
void databaseRemove(std::shared_ptr<Database> db); void databaseRemove(std::shared_ptr<Database> db);
void databaseAdd(std::shared_ptr<Database> db); void databaseAdd(std::shared_ptr<Database> db);
void success(const MethodCall &call, const Encodable &result = nullptr); void sendSuccess(const MethodCall &call, const Encodable &result = nullptr);
void error(const MethodCall &call, void sendError(const MethodCall &call,
const std::string &error, const std::string &error,
const std::string &message, const std::string &message,
const std::string &desc = "", const std::string &desc = "",
@ -59,13 +54,13 @@ private:
Encodable::Map makeOpenResult(int64_t dbID, bool recovered, bool recoveredInTransaction); Encodable::Map makeOpenResult(int64_t dbID, bool recovered, bool recoveredInTransaction);
private: private:
std::mutex mutex; std::mutex m_mutex;
std::unordered_map<std::string, std::shared_ptr<Database>> singletonDatabases; std::unordered_map<std::string, std::shared_ptr<Database>> m_singleInstanceDatabases;
std::unordered_map<int64_t, std::shared_ptr<Database>> databases; std::unordered_map<int64_t, std::shared_ptr<Database>> m_databases;
int64_t dbID = 0; int64_t m_dbID = 0;
Logger logger; Logger m_logger;
bool queryAsMapList = false; bool m_queryAsMapList = false;
AsyncQueue asynq; AsyncQueue m_asyncQueue;
}; };
#endif /* FLUTTER_PLUGIN_SQFLITE_H */ #endif /* FLUTTER_PLUGIN_SQFLITE_H */

30
packages/sqflite/sqflite_aurora/aurora/include/sqflite_aurora/utils.h

@ -0,0 +1,30 @@
/*
* Copyright (c) 2023. Open Mobile Platform LLC.
* License: Proprietary.
*/
#ifndef FLUTTER_PLUGIN_SQFLITE_UTILS_H
#define FLUTTER_PLUGIN_SQFLITE_UTILS_H
#include <optional>
#include <string>
namespace utils {
class error final
{
public:
explicit error(std::string message);
error() = default;
explicit operator bool() const;
const std::string &message() const;
static error none();
private:
std::optional<std::string> m_message;
};
} /* namespace utils */
#endif /* FLUTTER_PLUGIN_SQFLITE_UTILS_H */

6
packages/sqflite/sqflite_aurora/aurora/lib/asynq.cpp → packages/sqflite/sqflite_aurora/aurora/lib/async_queue.cpp

@ -2,7 +2,7 @@
* Copyright (c) 2023. Open Mobile Platform LLC. * Copyright (c) 2023. Open Mobile Platform LLC.
* License: Proprietary. * License: Proprietary.
*/ */
#include <sqflite_aurora/asynq.h> #include <sqflite_aurora/async_queue.h>
AsyncQueue::AsyncQueue() AsyncQueue::AsyncQueue()
: m_running(false) : m_running(false)
@ -15,7 +15,7 @@ AsyncQueue::~AsyncQueue()
m_thread.join(); m_thread.join();
} }
void AsyncQueue::Push(const Task &task) void AsyncQueue::push(const Task &task)
{ {
if (!m_running) { if (!m_running) {
m_running = true; m_running = true;
@ -38,8 +38,8 @@ void AsyncQueue::run()
const auto task = m_tasks.front(); const auto task = m_tasks.front();
m_tasks.pop(); m_tasks.pop();
lock.unlock();
lock.unlock();
task(); task();
} }
} }

280
packages/sqflite/sqflite_aurora/aurora/lib/database.cpp

@ -10,11 +10,13 @@
namespace { namespace {
void addError(Encodable::List &results, const std::string &error) void addError(Encodable::List &results, const utils::error &error)
{ {
if (error) {
results.emplace_back(Encodable::Map{ results.emplace_back(Encodable::Map{
{"error", Encodable::Map{{"message", error}}}, {"error", Encodable::Map{{"message", error.message()}}},
}); });
}
} }
template<typename T> template<typename T>
@ -25,72 +27,72 @@ void addResult(Encodable::List &results, const T &result)
} /* namespace */ } /* namespace */
Database::Database(int id, const std::string &path, bool singleton, const Logger &logger) Database::Database(int id, const std::string &path, bool singleInstance, const Logger &logger)
: id(id) : m_id(id)
, path(path) , m_path(path)
, isSingleInstance(singleton) , m_isSingleInstance(singleInstance)
, logger(logger.LogLevel(), logger.Tag() + "-db-" + std::to_string(id)) , m_logger(logger.logLevel(), logger.tag() + "-db-" + std::to_string(id))
, transactionID(0) , m_transactionID(0)
, currentTransactionID(TransactionID::None) , m_currentTransactionID(TransactionID::None)
, cursorID(0) , m_cursorID(0)
, db(nullptr) , m_db(nullptr)
{} {}
Database::~Database() Database::~Database()
{ {
Close(); close();
} }
std::optional<std::string> Database::Open() utils::error Database::open()
{ {
const auto error = this->createParentDir(); const auto error = createParentDir();
if (error) if (error)
return error; return error;
int result_code = sqlite3_open_v2(this->path.c_str(), int result_code = sqlite3_open_v2(m_path.c_str(),
&this->db, &m_db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
nullptr); nullptr);
if (result_code != SQLITE_OK) if (result_code != SQLITE_OK)
return this->currentErrorMessage(); return utils::error(currentErrorMessage());
this->isReadOnly = false; m_isReadOnly = false;
return std::nullopt; return utils::error::none();
} }
std::optional<std::string> Database::OpenReadOnly() utils::error Database::openReadOnly()
{ {
const auto error = this->createParentDir(); const auto error = createParentDir();
if (error) if (error)
return error; return error;
int result_code = sqlite3_open_v2(this->path.c_str(), &this->db, SQLITE_OPEN_READONLY, nullptr); int result_code = sqlite3_open_v2(m_path.c_str(), &m_db, SQLITE_OPEN_READONLY, nullptr);
if (result_code != SQLITE_OK) if (result_code != SQLITE_OK)
return this->currentErrorMessage(); return utils::error(currentErrorMessage());
this->isReadOnly = true; m_isReadOnly = true;
return std::nullopt; return utils::error::none();
} }
std::optional<std::string> Database::Close() utils::error Database::close()
{ {
if (sqlite3_close_v2(this->db) != SQLITE_OK) if (sqlite3_close_v2(m_db) != SQLITE_OK)
return this->currentErrorMessage(); return utils::error(currentErrorMessage());
this->db = nullptr; m_db = nullptr;
this->pendingSqlCallbacks = {}; m_pendingSqlCallbacks = {};
return std::nullopt; return utils::error::none();
} }
std::optional<std::string> Database::Execute(const std::string &sql, const Encodable::List &args) utils::error Database::execute(const std::string &sql, const Encodable::List &args)
{ {
sqlite3_stmt *stmt = nullptr; sqlite3_stmt *stmt = nullptr;
if (sqlite3_prepare_v2(this->db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) if (sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK)
return this->currentErrorMessage(); return utils::error(currentErrorMessage());
const auto error = this->bindStmtArgs(stmt, args); const auto error = bindStmtArgs(stmt, args);
if (error) { if (error) {
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
@ -107,23 +109,23 @@ std::optional<std::string> Database::Execute(const std::string &sql, const Encod
break; break;
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
return this->currentErrorMessage(); return utils::error(currentErrorMessage());
} }
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
return std::nullopt; return utils::error::none();
} }
std::optional<std::string> Database::Query(const std::string &sql, utils::error Database::query(const std::string &sql,
const Encodable::List &args, const Encodable::List &args,
Encodable::Map &result) Encodable::Map &result)
{ {
sqlite3_stmt *stmt = nullptr; sqlite3_stmt *stmt = nullptr;
if (sqlite3_prepare_v2(this->db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) if (sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK)
return this->currentErrorMessage(); return utils::error(currentErrorMessage());
const auto error = this->bindStmtArgs(stmt, args); const auto error = bindStmtArgs(stmt, args);
if (error) { if (error) {
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
@ -184,206 +186,206 @@ std::optional<std::string> Database::Query(const std::string &sql,
break; break;
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
return this->currentErrorMessage(); return utils::error(currentErrorMessage());
} }
result = Encodable::Map{{"columns", columns}, {"rows", rows}}; result = Encodable::Map{{"columns", columns}, {"rows", rows}};
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
return std::nullopt; return utils::error::none();
} }
std::optional<std::string> Database::QueryWithPageSize(const std::string &sql, utils::error Database::queryWithPageSize(const std::string &sql,
const Encodable::List &args, const Encodable::List &args,
int64_t pageSize, int64_t pageSize,
Encodable::Map &result) Encodable::Map &result)
{ {
sqlite3_stmt *stmt = nullptr; sqlite3_stmt *stmt = nullptr;
if (sqlite3_prepare_v2(this->db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) if (sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK)
return this->currentErrorMessage(); return utils::error(currentErrorMessage());
const auto error = this->bindStmtArgs(stmt, args); const auto error = bindStmtArgs(stmt, args);
if (error) if (error)
return error; return error;
this->cursorID += 1; m_cursorID += 1;
this->cursors[cursorID] = Cursor{this->cursorID, stmt, pageSize}; m_cursors[m_cursorID] = Cursor{m_cursorID, stmt, pageSize};
return resultFromCursor(this->cursors[cursorID], result); return resultFromCursor(m_cursors[m_cursorID], result);
} }
std::optional<std::string> Database::QueryCursorNext(int cursorID, utils::error Database::queryCursorNext(int cursorID,
bool cancel, bool cancel,
Encodable::Map &result) Encodable::Map &result)
{ {
this->logger.verb() << "querying cursor next (ID=" << cursorID << "; CANCEL=" << cancel << ")" m_logger.verb() << "querying cursor next (ID=" << cursorID << "; CANCEL=" << cancel << ")"
<< std::endl; << std::endl;
if (!this->cursors.count(cursorID)) if (!m_cursors.count(cursorID))
return "cursor not found"; return utils::error("cursor not found");
const Cursor &cursor = this->cursors[cursorID]; const Cursor &cursor = m_cursors[cursorID];
if (cancel) { if (cancel) {
this->closeCursor(cursor); closeCursor(cursor);
return std::nullopt; return utils::error::none();
} }
return this->resultFromCursor(cursor, result); return resultFromCursor(cursor, result);
} }
std::optional<std::string> Database::Insert(const std::string &sql, utils::error Database::insert(const std::string &sql,
const Encodable::List &args, const Encodable::List &args,
int &insertID) int &insertID)
{ {
if (this->isReadOnly) if (m_isReadOnly)
return "database is readonly"; return utils::error("database is readonly");
const auto error = this->Execute(sql, args); const auto error = execute(sql, args);
if (error) if (error)
return error; return error;
const int updated = sqlite3_changes(this->db); const int updated = sqlite3_changes(m_db);
this->logger.sql() << "rows updated: " << updated << std::endl; m_logger.sql() << "rows updated: " << updated << std::endl;
if (updated == 0) { if (updated == 0) {
insertID = 0; insertID = 0;
return std::nullopt; return utils::error::none();
} }
insertID = sqlite3_last_insert_rowid(this->db); insertID = sqlite3_last_insert_rowid(m_db);
this->logger.sql() << "last inserted row id: " << insertID << std::endl; m_logger.sql() << "last inserted row id: " << insertID << std::endl;
return std::nullopt; return utils::error::none();
} }
std::optional<std::string> Database::Update(const std::string &sql, utils::error Database::update(const std::string &sql,
const Encodable::List &args, const Encodable::List &args,
int &updated) int &updated)
{ {
if (this->isReadOnly) if (m_isReadOnly)
return "database is readonly"; return utils::error("database is readonly");
const auto error = this->Execute(sql, args); const auto error = execute(sql, args);
if (error) if (error)
return error; return error;
updated = sqlite3_changes(this->db); updated = sqlite3_changes(m_db);
this->logger.sql() << "rows updated: " << updated << std::endl; m_logger.sql() << "rows updated: " << updated << std::endl;
return std::nullopt; return utils::error::none();
} }
void Database::ProcessSqlCommand(int transactionID, const SqlCommandCallback &callback) void Database::processSqlCommand(int transactionID, const SqlCommandCallback &callback)
{ {
if (this->currentTransactionID == TransactionID::None) { if (m_currentTransactionID == TransactionID::None) {
callback(); callback();
return; return;
} }
if (transactionID == this->currentTransactionID || transactionID == TransactionID::Force) { if (transactionID == m_currentTransactionID || transactionID == TransactionID::Force) {
callback(); callback();
if (this->currentTransactionID == TransactionID::None) { if (m_currentTransactionID == TransactionID::None) {
while (!this->pendingSqlCallbacks.empty() && this->IsOpen()) { while (!m_pendingSqlCallbacks.empty() && isOpen()) {
const auto &pendingCallback = this->pendingSqlCallbacks.front(); const auto &pendingCallback = m_pendingSqlCallbacks.front();
pendingCallback(); pendingCallback();
this->pendingSqlCallbacks.pop(); m_pendingSqlCallbacks.pop();
} }
} }
return; return;
} }
this->pendingSqlCallbacks.push(callback); m_pendingSqlCallbacks.push(callback);
} }
void Database::EnterInTransaction() void Database::enterInTransaction()
{ {
this->transactionID += 1; m_transactionID += 1;
this->currentTransactionID = this->transactionID; m_currentTransactionID = m_transactionID;
} }
void Database::LeaveTransaction() void Database::leaveTransaction()
{ {
this->currentTransactionID = TransactionID::None; m_currentTransactionID = TransactionID::None;
} }
int Database::CurrentTransactionID() int Database::currentTransactionID()
{ {
return this->currentTransactionID; return m_currentTransactionID;
} }
bool Database::IsOpen() const bool Database::isOpen() const
{ {
return this->db != nullptr; return m_db != nullptr;
} }
const std::string &Database::Path() const const std::string &Database::path() const
{ {
return this->path; return m_path;
} }
bool Database::IsSingleInstance() const bool Database::isSingleInstance() const
{ {
return this->isSingleInstance; return m_isSingleInstance;
} }
bool Database::IsReadOnly() const bool Database::isReadOnly() const
{ {
return this->isReadOnly; return m_isReadOnly;
} }
bool Database::IsInTransaction() const bool Database::isInTransaction() const
{ {
return this->currentTransactionID != TransactionID::None; return m_currentTransactionID != TransactionID::None;
} }
int64_t Database::ID() const int64_t Database::id() const
{ {
return this->id; return m_id;
} }
Logger::Level Database::LogLevel() const Logger::Level Database::logLevel() const
{ {
return this->logger.LogLevel(); return m_logger.logLevel();
} }
bool Database::IsInMemory() const bool Database::isInMemory() const
{ {
return this->path.empty() || this->path == ":memory:"; return m_path.empty() || m_path == ":memory:";
} }
std::string Database::currentErrorMessage() std::string Database::currentErrorMessage()
{ {
const auto message = sqlite3_errmsg(this->db); const auto message = sqlite3_errmsg(m_db);
const auto code = sqlite3_extended_errcode(this->db); const auto code = sqlite3_extended_errcode(m_db);
return std::string(message) + " (" + std::to_string(code) + ")"; return std::string(message) + " (" + std::to_string(code) + ")";
} }
std::optional<std::string> Database::createParentDir() utils::error Database::createParentDir()
{ {
if (this->IsInMemory()) if (isInMemory())
return std::nullopt; return utils::error::none();
const auto parentDir = std::filesystem::path(this->path).parent_path(); const auto parentDir = std::filesystem::path(m_path).parent_path();
if (std::filesystem::exists(parentDir)) if (std::filesystem::exists(parentDir))
return std::nullopt; return utils::error::none();
if (std::filesystem::create_directories(parentDir)) if (std::filesystem::create_directories(parentDir))
return std::nullopt; return utils::error::none();
return "couldn't create parent directory"; return utils::error("couldn't create parent directory");
} }
std::optional<std::string> Database::bindStmtArgs(sqlite3_stmt *stmt, const Encodable::List &args) utils::error Database::bindStmtArgs(sqlite3_stmt *stmt, const Encodable::List &args)
{ {
int result = SQLITE_OK; int result = SQLITE_OK;
@ -451,12 +453,12 @@ std::optional<std::string> Database::bindStmtArgs(sqlite3_stmt *stmt, const Enco
for (const auto &entry : arg.GetList()) { for (const auto &entry : arg.GetList()) {
if (!entry.IsInt()) if (!entry.IsInt())
return "only list of bytes is supported for statement parameter"; return utils::error("only list of bytes is supported for statement parameter");
const auto value = entry.GetInt(); const auto value = entry.GetInt();
if (value < 0 || value > 255) if (value < 0 || value > 255)
return "only list of bytes is supported for statement parameter"; return utils::error("only list of bytes is supported for statement parameter");
container.push_back(static_cast<uint8_t>(value)); container.push_back(static_cast<uint8_t>(value));
} }
@ -467,25 +469,25 @@ std::optional<std::string> Database::bindStmtArgs(sqlite3_stmt *stmt, const Enco
container.size(), container.size(),
SQLITE_TRANSIENT); SQLITE_TRANSIENT);
} else { } else {
return "statement parameter has invalid type"; return utils::error("statement parameter has invalid type");
} }
if (result != SQLITE_OK) if (result != SQLITE_OK)
return this->currentErrorMessage(); return utils::error(currentErrorMessage());
} }
this->logger.sql() << sqlite3_expanded_sql(stmt) << std::endl; m_logger.sql() << sqlite3_expanded_sql(stmt) << std::endl;
return std::nullopt; return utils::error::none();
} }
void Database::closeCursor(const Cursor &cursor) void Database::closeCursor(const Cursor &cursor)
{ {
logger.verb() << "closing cursor (ID=" << cursor.id << ")" << std::endl; m_logger.verb() << "closing cursor (ID=" << cursor.id << ")" << std::endl;
sqlite3_finalize(cursor.stmt); sqlite3_finalize(cursor.stmt);
this->cursors.erase(cursor.id); m_cursors.erase(cursor.id);
} }
std::optional<std::string> Database::resultFromCursor(const Cursor &cursor, Encodable::Map &result) utils::error Database::resultFromCursor(const Cursor &cursor, Encodable::Map &result)
{ {
Encodable::List columns; Encodable::List columns;
@ -540,12 +542,12 @@ std::optional<std::string> Database::resultFromCursor(const Cursor &cursor, Enco
} }
if (status == SQLITE_DONE) { if (status == SQLITE_DONE) {
this->closeCursor(cursor); closeCursor(cursor);
break; break;
} }
this->closeCursor(cursor); closeCursor(cursor);
return this->currentErrorMessage(); return utils::error(currentErrorMessage());
} }
result = Encodable::Map{{"columns", columns}, {"rows", rows}}; result = Encodable::Map{{"columns", columns}, {"rows", rows}};
@ -553,10 +555,10 @@ std::optional<std::string> Database::resultFromCursor(const Cursor &cursor, Enco
if (status != SQLITE_DONE) if (status != SQLITE_DONE)
result.insert({ARG_CURSOR_ID, cursor.id}); result.insert({ARG_CURSOR_ID, cursor.id});
return std::nullopt; return utils::error::none();
} }
std::optional<std::string> Database::Batch(const std::vector<Operation> &operations, utils::error Database::batch(const std::vector<Operation> &operations,
bool continueOnError, bool continueOnError,
Encodable::List &results) Encodable::List &results)
{ {
@ -565,13 +567,13 @@ std::optional<std::string> Database::Batch(const std::vector<Operation> &operati
if (method == METHOD_INSERT) { if (method == METHOD_INSERT) {
int insertID = 0; int insertID = 0;
const auto error = this->Insert(operation.sql, operation.arguments, insertID); const auto error = insert(operation.sql, operation.arguments, insertID);
if (error) { if (error) {
if (!continueOnError) if (!continueOnError)
return error; return error;
addError(results, *error); addError(results, error);
continue; continue;
} }
@ -584,13 +586,13 @@ std::optional<std::string> Database::Batch(const std::vector<Operation> &operati
} }
if (method == METHOD_EXECUTE) { if (method == METHOD_EXECUTE) {
const auto error = this->Execute(operation.sql, operation.arguments); const auto error = execute(operation.sql, operation.arguments);
if (error) { if (error) {
if (!continueOnError) if (!continueOnError)
return error; return error;
addError(results, *error); addError(results, error);
continue; continue;
} }
@ -600,13 +602,13 @@ std::optional<std::string> Database::Batch(const std::vector<Operation> &operati
if (method == METHOD_QUERY) { if (method == METHOD_QUERY) {
Encodable::Map result; Encodable::Map result;
const auto error = this->Query(operation.sql, operation.arguments, result); const auto error = query(operation.sql, operation.arguments, result);
if (error) { if (error) {
if (!continueOnError) if (!continueOnError)
return error; return error;
addError(results, *error); addError(results, error);
continue; continue;
} }
@ -616,13 +618,13 @@ std::optional<std::string> Database::Batch(const std::vector<Operation> &operati
if (method == METHOD_UPDATE) { if (method == METHOD_UPDATE) {
int updated = 0; int updated = 0;
const auto error = this->Update(operation.sql, operation.arguments, updated); const auto error = update(operation.sql, operation.arguments, updated);
if (error) { if (error) {
if (!continueOnError) if (!continueOnError)
return error; return error;
addError(results, *error); addError(results, error);
continue; continue;
} }
@ -631,5 +633,5 @@ std::optional<std::string> Database::Batch(const std::vector<Operation> &operati
} }
} }
return std::nullopt; return utils::error::none();
} }

34
packages/sqflite/sqflite_aurora/aurora/lib/logger.cpp

@ -6,43 +6,43 @@
#include <sqflite_aurora/logger.h> #include <sqflite_aurora/logger.h>
Logger::Logger(Level level, const std::string &tag) Logger::Logger(Level level, const std::string &tag)
: level(level) : m_level(level)
, tag(tag) , m_tag(tag)
, devnull(0) , m_devnull(0)
{} {}
Logger::Level Logger::LogLevel() const Logger::Level Logger::logLevel() const
{ {
return this->level; return m_level;
} }
void Logger::SetLogLevel(Level level) void Logger::setLogLevel(Level level)
{ {
this->level = level; m_level = level;
} }
std::string Logger::Tag() const std::string Logger::tag() const
{ {
return this->tag; return m_tag;
} }
void Logger::SetTag(const std::string &tag) void Logger::setTag(const std::string &tag)
{ {
this->tag = tag; m_tag = tag;
} }
std::ostream &Logger::verb() std::ostream &Logger::verb()
{ {
if (this->level >= Level::Verbose) if (m_level >= Level::Verbose)
return loginfo << (this->tag.empty() ? "" : "[" + this->tag + "] "); return loginfo << (m_tag.empty() ? "" : "[" + m_tag + "] ");
return this->devnull; return m_devnull;
} }
std::ostream &Logger::sql() std::ostream &Logger::sql()
{ {
if (this->level >= Level::Sql) if (m_level >= Level::Sql)
return loginfo << (this->tag.empty() ? "" : "[" + this->tag + "] "); return loginfo << (m_tag.empty() ? "" : "[" + m_tag + "] ");
return this->devnull; return m_devnull;
} }

370
packages/sqflite/sqflite_aurora/aurora/lib/sqflite_aurora_plugin.cpp

@ -13,7 +13,7 @@
namespace { namespace {
int64_t GetTransactionID(const Encodable &args) int64_t getTransactionID(const Encodable &args)
{ {
if (!args.HasKey(ARG_TRANSACTION_ID)) if (!args.HasKey(ARG_TRANSACTION_ID))
return static_cast<int64_t>(Database::TransactionID::None); return static_cast<int64_t>(Database::TransactionID::None);
@ -27,7 +27,7 @@ int64_t GetTransactionID(const Encodable &args)
return args[ARG_TRANSACTION_ID].GetInt(); return args[ARG_TRANSACTION_ID].GetInt();
} }
Encodable::List GetSqlArguments(const Encodable &args) Encodable::List getSqlArguments(const Encodable &args)
{ {
if (!args.HasKey(ARG_SQL_ARGUMENTS)) if (!args.HasKey(ARG_SQL_ARGUMENTS))
return Encodable::List{}; return Encodable::List{};
@ -44,15 +44,15 @@ Encodable::List GetSqlArguments(const Encodable &args)
} /* namespace */ } /* namespace */
SqfliteAuroraPlugin::SqfliteAuroraPlugin() SqfliteAuroraPlugin::SqfliteAuroraPlugin()
: dbID(0) : m_dbID(0)
, logger(Logger::Level::None, "sqflite") , m_logger(Logger::Level::None, "sqflite")
{} {}
void SqfliteAuroraPlugin::RegisterWithRegistrar(PluginRegistrar &registrar) void SqfliteAuroraPlugin::RegisterWithRegistrar(PluginRegistrar &registrar)
{ {
registrar.RegisterMethodChannel("com.tekartik.sqflite", registrar.RegisterMethodChannel("com.tekartik.sqflite",
MethodCodecType::Standard, MethodCodecType::Standard,
[this](const MethodCall &call) { this->onMethodCall(call); }); [this](const MethodCall &call) { onMethodCall(call); });
} }
void SqfliteAuroraPlugin::onMethodCall(const MethodCall &call) void SqfliteAuroraPlugin::onMethodCall(const MethodCall &call)
@ -60,76 +60,76 @@ void SqfliteAuroraPlugin::onMethodCall(const MethodCall &call)
const auto &method = call.GetMethod(); const auto &method = call.GetMethod();
if (method == METHOD_GET_PLATFORM_VERSION) { if (method == METHOD_GET_PLATFORM_VERSION) {
this->onPlatformVersionCall(call); onPlatformVersionCall(call);
return; return;
} }
if (method == METHOD_OPEN_DATABASE) { if (method == METHOD_OPEN_DATABASE) {
this->onOpenDatabaseCall(call); onOpenDatabaseCall(call);
return; return;
} }
if (method == METHOD_CLOSE_DATABASE) { if (method == METHOD_CLOSE_DATABASE) {
this->onCloseDatabaseCall(call); onCloseDatabaseCall(call);
return; return;
} }
if (method == METHOD_DELETE_DATABASE) { if (method == METHOD_DELETE_DATABASE) {
this->onDeleteDatabaseCall(call); onDeleteDatabaseCall(call);
return; return;
} }
if (method == METHOD_DATABASE_EXISTS) { if (method == METHOD_DATABASE_EXISTS) {
this->onDatabaseExistsCall(call); onDatabaseExistsCall(call);
return; return;
} }
if (method == METHOD_GET_DATABASES_PATH) { if (method == METHOD_GET_DATABASES_PATH) {
this->onGetDatabasesPathCall(call); onGetDatabasesPathCall(call);
return; return;
} }
if (method == METHOD_OPTIONS) { if (method == METHOD_OPTIONS) {
this->onOptionsCall(call); onOptionsCall(call);
return; return;
} }
if (method == METHOD_DEBUG) { if (method == METHOD_DEBUG) {
this->onDebugCall(call); onDebugCall(call);
return; return;
} }
if (method == METHOD_EXECUTE) { if (method == METHOD_EXECUTE) {
this->onExecuteCall(call); onExecuteCall(call);
return; return;
} }
if (method == METHOD_QUERY) { if (method == METHOD_QUERY) {
this->onQueryCall(call); onQueryCall(call);
return; return;
} }
if (method == METHOD_QUERY_CURSOR_NEXT) { if (method == METHOD_QUERY_CURSOR_NEXT) {
this->onQueryCursorNextCall(call); onQueryCursorNextCall(call);
return; return;
} }
if (method == METHOD_UPDATE) { if (method == METHOD_UPDATE) {
this->onUpdateCall(call); onUpdateCall(call);
return; return;
} }
if (method == METHOD_INSERT) { if (method == METHOD_INSERT) {
this->onInsertCall(call); onInsertCall(call);
return; return;
} }
if (method == METHOD_BATCH) { if (method == METHOD_BATCH) {
this->onBatchCall(call); onBatchCall(call);
return; return;
} }
this->success(call); sendSuccess(call);
} }
void SqfliteAuroraPlugin::onPlatformVersionCall(const MethodCall &call) void SqfliteAuroraPlugin::onPlatformVersionCall(const MethodCall &call)
@ -141,122 +141,114 @@ void SqfliteAuroraPlugin::onPlatformVersionCall(const MethodCall &call)
if (line.rfind("VERSION_ID=") != 0) if (line.rfind("VERSION_ID=") != 0)
continue; continue;
this->success(call, "Aurora " + line.substr(11)); sendSuccess(call, "Aurora " + line.substr(11));
return; return;
} }
this->success(call, "Aurora"); sendSuccess(call, "Aurora");
} }
void SqfliteAuroraPlugin::onOpenDatabaseCall(const MethodCall &call) void SqfliteAuroraPlugin::onOpenDatabaseCall(const MethodCall &call)
{ {
const auto &args = call.GetArguments(); const auto dbPath = call.GetArgument<Encodable::String>(ARG_PATH);
const auto readOnly = call.GetArgument<Encodable::Boolean>(ARG_READ_ONLY, false);
const auto dbPath = args[ARG_PATH].GetString();
const auto readOnly = args.HasKey(ARG_READ_ONLY) ? args[ARG_READ_ONLY].GetBoolean() : false;
const auto inMemory = dbPath.empty() || dbPath == ":memory:"; const auto inMemory = dbPath.empty() || dbPath == ":memory:";
const auto singleton = args[ARG_SINGLE_INSTANCE].GetBoolean() && !inMemory; const auto isSingleInstance = call.GetArgument<Encodable::Boolean>(ARG_SINGLE_INSTANCE)
&& !inMemory;
if (singleton) { if (isSingleInstance) {
const auto db = this->databaseByPath(dbPath); const auto db = databaseByPath(dbPath);
if (db) { if (db) {
if (db->IsOpen()) { if (db->isOpen()) {
this->logger.verb() << "re-opened single instance database" m_logger.verb() << "re-opened single instance database"
<< (db->IsInTransaction() ? "(in transaction) " : "") << (db->isInTransaction() ? "(in transaction) " : "") << db->id()
<< db->ID() << " " << db->Path() << std::endl; << " " << db->path() << std::endl;
this->success(call, makeOpenResult(db->ID(), true, db->IsInTransaction())); sendSuccess(call, makeOpenResult(db->id(), true, db->isInTransaction()));
return; return;
} }
this->logger.verb() << "single instance database " << db->Path() << " not opened" m_logger.verb() << "single instance database " << db->path() << " not opened"
<< std::endl; << std::endl;
} }
} }
const auto db = std::make_shared<Database>(++dbID, dbPath, singleton, logger); const auto db = std::make_shared<Database>(++m_dbID, dbPath, isSingleInstance, m_logger);
this->asynq.Push([this, db, readOnly, call] { m_asyncQueue.push([this, db, readOnly, call] {
this->logger.sql() << "open database " + db->Path() + " (ID=" << db->ID() << ")" m_logger.sql() << "open database " + db->path() + " (ID=" << db->id() << ")" << std::endl;
<< std::endl;
const auto error = readOnly ? db->OpenReadOnly() : db->Open(); const auto error = readOnly ? db->openReadOnly() : db->open();
if (error) { if (error) {
this->error(call, ERROR_OPEN, db->Path(), *error); sendError(call, ERROR_OPEN, db->path(), error.message());
return; return;
} }
this->databaseAdd(db); databaseAdd(db);
this->success(call, makeOpenResult(db->ID(), false, false)); sendSuccess(call, makeOpenResult(db->id(), false, false));
}); });
} }
void SqfliteAuroraPlugin::onCloseDatabaseCall(const MethodCall &call) void SqfliteAuroraPlugin::onCloseDatabaseCall(const MethodCall &call)
{ {
const auto &args = call.GetArguments(); const auto dbID = call.GetArgument<Encodable::Int>(ARG_ID);
const auto dbID = args[ARG_ID].GetInt();
const auto db = databaseByID(dbID); const auto db = databaseByID(dbID);
this->asynq.Push([this, db, dbID, call] { m_asyncQueue.push([this, db, dbID, call] {
if (!db) { if (!db) {
this->error(call, ERROR_CLOSED, "database closed", "ID=" + std::to_string(dbID) + ")"); sendError(call, ERROR_CLOSED, "database closed", "ID=" + std::to_string(dbID) + ")");
return; return;
} }
this->logger.sql() << "closing database with ID=" << db->ID() << std::endl; m_logger.sql() << "closing database with ID=" << db->id() << std::endl;
const auto error = db->Close(); const auto error = db->close();
if (error) { if (error) {
this->error(call, ERROR_CLOSE, db->Path(), *error); sendError(call, ERROR_CLOSE, db->path(), error.message());
return; return;
} }
this->databaseRemove(db); databaseRemove(db);
this->success(call); sendSuccess(call);
}); });
} }
void SqfliteAuroraPlugin::onDeleteDatabaseCall(const MethodCall &call) void SqfliteAuroraPlugin::onDeleteDatabaseCall(const MethodCall &call)
{ {
const auto &args = call.GetArguments(); const auto dbPath = call.GetArgument<Encodable::String>(ARG_PATH);
const auto dbPath = args[ARG_PATH].GetString();
const auto db = databaseByPath(dbPath); const auto db = databaseByPath(dbPath);
this->asynq.Push([this, db, dbPath, call] { m_asyncQueue.push([this, db, dbPath, call] {
if (db) { if (db) {
if (db->IsOpen()) { if (db->isOpen()) {
this->logger.verb() m_logger.verb() << "close database " << db->path() << " (ID=" << db->id() << ")"
<< "close database " << db->Path() << " (ID=" << db->ID() << ")" << std::endl; << std::endl;
const auto error = db->Close(); const auto error = db->close();
if (error) { if (error) {
this->error(call, ERROR_CLOSE, db->Path(), *error); sendError(call, ERROR_CLOSE, db->path(), error.message());
return; return;
} }
} }
this->databaseRemove(db); databaseRemove(db);
} }
if (std::filesystem::exists(dbPath)) { if (std::filesystem::exists(dbPath)) {
this->logger.verb() << "delete not opened database " << dbPath << std::endl; m_logger.verb() << "delete not opened database " << dbPath << std::endl;
std::filesystem::remove(dbPath); std::filesystem::remove(dbPath);
} }
this->success(call); sendSuccess(call);
}); });
} }
void SqfliteAuroraPlugin::onDatabaseExistsCall(const MethodCall &call) void SqfliteAuroraPlugin::onDatabaseExistsCall(const MethodCall &call)
{ {
const auto &args = call.GetArguments(); const auto dbPath = call.GetArgument<Encodable::String>(ARG_PATH);
const auto dbPath = args[ARG_PATH].GetString(); sendSuccess(call, std::filesystem::exists(dbPath));
this->success(call, std::filesystem::exists(dbPath));
} }
void SqfliteAuroraPlugin::onGetDatabasesPathCall(const MethodCall &call) void SqfliteAuroraPlugin::onGetDatabasesPathCall(const MethodCall &call)
@ -264,48 +256,46 @@ void SqfliteAuroraPlugin::onGetDatabasesPathCall(const MethodCall &call)
const auto home = std::getenv("HOME"); const auto home = std::getenv("HOME");
if (home == nullptr) { if (home == nullptr) {
this->error(call, ERROR_INTERNAL, "environment variable $HOME not found"); sendError(call, ERROR_INTERNAL, "environment variable $HOME not found");
return; return;
} }
const auto [orgname, appname] = Application::GetID(); const auto [orgname, appname] = Application::GetID();
const auto directory = std::filesystem::path(home) / ".local/share" / orgname / appname; const auto directory = std::filesystem::path(home) / ".local/share" / orgname / appname;
this->success(call, directory.generic_string()); sendSuccess(call, directory.generic_string());
} }
void SqfliteAuroraPlugin::onOptionsCall(const MethodCall &call) void SqfliteAuroraPlugin::onOptionsCall(const MethodCall &call)
{ {
const auto &args = call.GetArguments(); const auto level = call.GetArgument<Encodable::Int>(ARG_LOG_LEVEL);
const auto level = args[ARG_LOG_LEVEL].GetInt(); m_logger.setLogLevel(static_cast<Logger::Level>(level));
this->logger.SetLogLevel(static_cast<Logger::Level>(level)); sendSuccess(call);
this->success(call);
} }
void SqfliteAuroraPlugin::onDebugCall(const MethodCall &call) void SqfliteAuroraPlugin::onDebugCall(const MethodCall &call)
{ {
const auto &args = call.GetArguments(); const auto cmd = call.GetArgument<Encodable::String>(ARG_COMMAND);
const auto cmd = args[ARG_COMMAND].GetString();
std::lock_guard<std::mutex> lock(this->mutex); std::lock_guard<std::mutex> lock(m_mutex);
Encodable::Map result; Encodable::Map result;
if (cmd == "get") { if (cmd == "get") {
if (this->logger.LogLevel() > Logger::Level::None) if (m_logger.logLevel() > Logger::Level::None)
result.emplace(ARG_LOG_LEVEL, static_cast<Encodable::Int>(this->logger.LogLevel())); result.emplace(ARG_LOG_LEVEL, static_cast<Encodable::Int>(m_logger.logLevel()));
if (!this->databases.empty()) { if (!m_databases.empty()) {
Encodable::Map databases; Encodable::Map databases;
for (const auto &[id, db] : this->databases) { for (const auto &[id, db] : m_databases) {
Encodable::Map info; Encodable::Map info;
info.emplace(ARG_PATH, db->Path()); info.emplace(ARG_PATH, db->path());
info.emplace(ARG_SINGLE_INSTANCE, db->IsSingleInstance()); info.emplace(ARG_SINGLE_INSTANCE, db->isSingleInstance());
if (db->LogLevel() > Logger::Level::None) if (db->logLevel() > Logger::Level::None)
info.emplace(ARG_LOG_LEVEL, static_cast<Encodable::Int>(db->LogLevel())); info.emplace(ARG_LOG_LEVEL, static_cast<Encodable::Int>(db->logLevel()));
databases.emplace(std::to_string(id), info); databases.emplace(std::to_string(id), info);
} }
@ -314,211 +304,197 @@ void SqfliteAuroraPlugin::onDebugCall(const MethodCall &call)
} }
} }
this->success(call, result); sendSuccess(call, result);
} }
void SqfliteAuroraPlugin::onExecuteCall(const MethodCall &call) void SqfliteAuroraPlugin::onExecuteCall(const MethodCall &call)
{ {
const auto &args = call.GetArguments(); const auto dbID = call.GetArgument<Encodable::Int>(ARG_ID);
const auto sql = call.GetArgument<Encodable::String>(ARG_SQL);
const auto dbID = args[ARG_ID].GetInt(); const auto inTransactionChange = call.GetArgument<Encodable::Boolean>(ARG_IN_TRANSACTION, false);
const auto sql = args[ARG_SQL].GetString();
const auto sqlArgs = GetSqlArguments(args); const auto sqlArgs = getSqlArguments(call.GetArguments());
const auto inTransactionChange = args.HasKey(ARG_IN_TRANSACTION) const auto transactionID = getTransactionID(call.GetArguments());
? args[ARG_IN_TRANSACTION].GetBoolean()
: false;
const auto transactionID = GetTransactionID(args);
const auto enteringTransaction = inTransactionChange == true const auto enteringTransaction = inTransactionChange == true
&& transactionID == Database::TransactionID::None; && transactionID == Database::TransactionID::None;
const auto db = databaseByID(dbID); const auto db = databaseByID(dbID);
if (!db) { if (!db) {
this->error(call, ERROR_CLOSED, "database closed", "ID=" + std::to_string(dbID) + ")"); sendError(call, ERROR_CLOSED, "database closed", "ID=" + std::to_string(dbID) + ")");
return; return;
} }
this->asynq.Push( m_asyncQueue.push([this,
[this, db, sql, sqlArgs, inTransactionChange, enteringTransaction, transactionID, call] { db,
db->ProcessSqlCommand( sql,
sqlArgs,
inTransactionChange,
enteringTransaction,
transactionID, transactionID,
[this, db, sql, sqlArgs, inTransactionChange, enteringTransaction, call] { call] {
db->processSqlCommand(transactionID, [this, db, sql, sqlArgs, inTransactionChange, enteringTransaction, call] {
if (enteringTransaction) if (enteringTransaction)
db->EnterInTransaction(); db->enterInTransaction();
const auto error = db->Execute(sql, sqlArgs); const auto error = db->execute(sql, sqlArgs);
if (error) { if (error) {
db->LeaveTransaction(); db->leaveTransaction();
this->error(call, ERROR_INTERNAL, *error); sendError(call, ERROR_INTERNAL, error.message());
return; return;
} }
if (enteringTransaction) { if (enteringTransaction) {
this->success(call, sendSuccess(call, Encodable::Map{{ARG_TRANSACTION_ID, db->currentTransactionID()}});
Encodable::Map{
{ARG_TRANSACTION_ID, db->CurrentTransactionID()},
});
return; return;
} }
if (inTransactionChange == false) if (inTransactionChange == false)
db->LeaveTransaction(); db->leaveTransaction();
this->success(call); sendSuccess(call);
}); });
}); });
} }
void SqfliteAuroraPlugin::onQueryCall(const MethodCall &call) void SqfliteAuroraPlugin::onQueryCall(const MethodCall &call)
{ {
const auto &args = call.GetArguments(); const auto dbID = call.GetArgument<Encodable::Int>(ARG_ID);
const auto sql = call.GetArgument<Encodable::String>(ARG_SQL);
const auto dbID = args[ARG_ID].GetInt(); const auto pageSize = call.GetArgument<Encodable::Int>(ARG_CURSOR_PAGE_SIZE, -1);
const auto sql = args[ARG_SQL].GetString();
const auto sqlArgs = GetSqlArguments(args); const auto sqlArgs = getSqlArguments(call.GetArguments());
const auto transactionID = GetTransactionID(args); const auto transactionID = getTransactionID(call.GetArguments());
const auto pageSize = args.HasKey(ARG_CURSOR_PAGE_SIZE) ? args[ARG_CURSOR_PAGE_SIZE].GetInt()
: -1;
const auto db = databaseByID(dbID); const auto db = databaseByID(dbID);
if (!db) { if (!db) {
this->error(call, ERROR_CLOSED, "database closed", "ID=" + std::to_string(dbID) + ")"); sendError(call, ERROR_CLOSED, "database closed", "ID=" + std::to_string(dbID) + ")");
return; return;
} }
this->asynq.Push([this, db, sql, sqlArgs, transactionID, pageSize, call] { m_asyncQueue.push([this, db, sql, sqlArgs, transactionID, pageSize, call] {
db->ProcessSqlCommand(transactionID, [this, db, sql, sqlArgs, pageSize, call] { db->processSqlCommand(transactionID, [this, db, sql, sqlArgs, pageSize, call] {
Encodable::Map result; Encodable::Map result;
std::optional<std::string> error; utils::error error;
if (pageSize <= 0) if (pageSize <= 0)
error = db->Query(sql, sqlArgs, result); error = db->query(sql, sqlArgs, result);
else else
error = db->QueryWithPageSize(sql, sqlArgs, pageSize, result); error = db->queryWithPageSize(sql, sqlArgs, pageSize, result);
if (error) { if (error) {
this->error(call, ERROR_INTERNAL, *error); sendError(call, ERROR_INTERNAL, error.message());
return; return;
} }
this->success(call, result); sendSuccess(call, result);
}); });
}); });
} }
void SqfliteAuroraPlugin::onQueryCursorNextCall(const MethodCall &call) void SqfliteAuroraPlugin::onQueryCursorNextCall(const MethodCall &call)
{ {
const auto &args = call.GetArguments(); const auto dbID = call.GetArgument<Encodable::Int>(ARG_ID);
const auto cursorID = call.GetArgument<Encodable::Int>(ARG_CURSOR_ID);
const auto dbID = args[ARG_ID].GetInt(); const auto closeCursor = call.GetArgument<Encodable::Boolean>(ARG_CANCEL, false);
const auto cursorID = args[ARG_CURSOR_ID].GetInt();
const auto closeCursor = args.HasKey(ARG_CANCEL) ? args[ARG_CANCEL].GetBoolean() : false;
const auto transactionID = GetTransactionID(args);
const auto transactionID = getTransactionID(call.GetArguments());
const auto db = databaseByID(dbID); const auto db = databaseByID(dbID);
if (!db) { if (!db) {
this->error(call, ERROR_CLOSED, "database closed", "ID=" + std::to_string(dbID) + ")"); sendError(call, ERROR_CLOSED, "database closed", "ID=" + std::to_string(dbID) + ")");
return; return;
} }
this->asynq.Push([this, db, cursorID, closeCursor, transactionID, call] { m_asyncQueue.push([this, db, cursorID, closeCursor, transactionID, call] {
db->ProcessSqlCommand(transactionID, [this, db, cursorID, closeCursor, call] { db->processSqlCommand(transactionID, [this, db, cursorID, closeCursor, call] {
Encodable::Map result; Encodable::Map result;
const auto error = db->QueryCursorNext(cursorID, closeCursor, result); const auto error = db->queryCursorNext(cursorID, closeCursor, result);
if (error) { if (error) {
this->error(call, ERROR_INTERNAL, *error); sendError(call, ERROR_INTERNAL, error.message());
return; return;
} }
this->success(call, result); sendSuccess(call, result);
}); });
}); });
} }
void SqfliteAuroraPlugin::onUpdateCall(const MethodCall &call) void SqfliteAuroraPlugin::onUpdateCall(const MethodCall &call)
{ {
const auto &args = call.GetArguments(); const auto dbID = call.GetArgument<Encodable::Int>(ARG_ID);
const auto sql = call.GetArgument<Encodable::String>(ARG_SQL);
const auto dbID = args[ARG_ID].GetInt();
const auto sql = args[ARG_SQL].GetString();
const auto sqlArgs = GetSqlArguments(args);
const auto transactionID = GetTransactionID(args);
const auto sqlArgs = getSqlArguments(call.GetArguments());
const auto transactionID = getTransactionID(call.GetArguments());
const auto db = databaseByID(dbID); const auto db = databaseByID(dbID);
if (!db) { if (!db) {
this->error(call, ERROR_CLOSED, "database closed", "ID=" + std::to_string(dbID) + ")"); sendError(call, ERROR_CLOSED, "database closed", "ID=" + std::to_string(dbID) + ")");
return; return;
} }
this->asynq.Push([this, db, sql, sqlArgs, transactionID, call] { m_asyncQueue.push([this, db, sql, sqlArgs, transactionID, call] {
db->ProcessSqlCommand(transactionID, [this, db, sql, sqlArgs, call] { db->processSqlCommand(transactionID, [this, db, sql, sqlArgs, call] {
int updated = 0; int updated = 0;
const auto error = db->Update(sql, sqlArgs, updated); const auto error = db->update(sql, sqlArgs, updated);
if (error) { if (error) {
this->error(call, ERROR_INTERNAL, *error); sendError(call, ERROR_INTERNAL, error.message());
return; return;
} }
this->success(call, updated); sendSuccess(call, updated);
}); });
}); });
} }
void SqfliteAuroraPlugin::onInsertCall(const MethodCall &call) void SqfliteAuroraPlugin::onInsertCall(const MethodCall &call)
{ {
const auto &args = call.GetArguments(); const auto dbID = call.GetArgument<Encodable::Int>(ARG_ID);
const auto sql = call.GetArgument<Encodable::String>(ARG_SQL);
const auto dbID = args[ARG_ID].GetInt();
const auto sql = args[ARG_SQL].GetString();
const auto sqlArgs = GetSqlArguments(args);
const auto transactionID = GetTransactionID(args);
const auto sqlArgs = getSqlArguments(call.GetArguments());
const auto transactionID = getTransactionID(call.GetArguments());
const auto db = databaseByID(dbID); const auto db = databaseByID(dbID);
if (!db) { if (!db) {
this->error(call, ERROR_CLOSED, "database closed", "ID=" + std::to_string(dbID) + ")"); sendError(call, ERROR_CLOSED, "database closed", "ID=" + std::to_string(dbID) + ")");
return; return;
} }
this->asynq.Push([this, db, sql, sqlArgs, transactionID, call] { m_asyncQueue.push([this, db, sql, sqlArgs, transactionID, call] {
db->ProcessSqlCommand(transactionID, [this, db, sql, sqlArgs, call] { db->processSqlCommand(transactionID, [this, db, sql, sqlArgs, call] {
int insertID = 0; int insertID = 0;
const auto error = db->Insert(sql, sqlArgs, insertID); const auto error = db->insert(sql, sqlArgs, insertID);
if (error) { if (error) {
this->error(call, ERROR_INTERNAL, *error); sendError(call, ERROR_INTERNAL, error.message());
return; return;
} }
if (insertID == 0) if (insertID == 0)
this->success(call); sendSuccess(call);
else else
this->success(call, insertID); sendSuccess(call, insertID);
}); });
}); });
} }
void SqfliteAuroraPlugin::onBatchCall(const MethodCall &call) void SqfliteAuroraPlugin::onBatchCall(const MethodCall &call)
{ {
const auto &args = call.GetArguments(); const auto dbID = call.GetArgument<Encodable::Int>(ARG_ID);
const auto &operations = call.GetArgument<Encodable::List>(ARG_OPERATIONS);
const auto dbID = args[ARG_ID].GetInt(); const auto noResult = call.GetArgument<Encodable::Boolean>(ARG_NO_RESULT, false);
const auto &operations = args[ARG_OPERATIONS].GetList(); const auto continueOnError = call.GetArgument<Encodable::Boolean>(ARG_CONTINUE_ON_ERROR, false);
const auto noResult = args.HasKey(ARG_NO_RESULT) ? args[ARG_NO_RESULT].GetBoolean() : false;
const auto continueOnError = args.HasKey(ARG_CONTINUE_ON_ERROR)
? args[ARG_CONTINUE_ON_ERROR].GetBoolean()
: false;
const auto transactionID = GetTransactionID(args);
const auto transactionID = getTransactionID(call.GetArguments());
const auto db = databaseByID(dbID); const auto db = databaseByID(dbID);
if (!db) { if (!db) {
this->error(call, ERROR_CLOSED, "database closed", "ID=" + std::to_string(dbID) + ")"); sendError(call, ERROR_CLOSED, "database closed", "ID=" + std::to_string(dbID) + ")");
return; return;
} }
@ -527,76 +503,76 @@ void SqfliteAuroraPlugin::onBatchCall(const MethodCall &call)
for (const auto &operation : operations) { for (const auto &operation : operations) {
const auto method = operation[ARG_METHOD].GetString(); const auto method = operation[ARG_METHOD].GetString();
const auto sql = operation[ARG_SQL].GetString(); const auto sql = operation[ARG_SQL].GetString();
const auto sqlArgs = GetSqlArguments(operation); const auto sqlArgs = getSqlArguments(operation);
dbOperations.emplace_back(Database::Operation{method, sql, sqlArgs}); dbOperations.emplace_back(Database::Operation{method, sql, sqlArgs});
} }
this->asynq.Push([this, db, dbOperations, transactionID, continueOnError, noResult, call] { m_asyncQueue.push([this, db, dbOperations, transactionID, continueOnError, noResult, call] {
const auto command = [this, db, dbOperations, continueOnError, noResult, call] { const auto command = [this, db, dbOperations, continueOnError, noResult, call] {
Encodable::List results; Encodable::List results;
const auto error = db->Batch(dbOperations, continueOnError, results); const auto error = db->batch(dbOperations, continueOnError, results);
if (error) { if (error) {
this->error(call, ERROR_INTERNAL, *error); sendError(call, ERROR_INTERNAL, error.message());
return; return;
} }
if (noResult) if (noResult)
this->success(call); sendSuccess(call);
else else
this->success(call, results); sendSuccess(call, results);
}; };
db->ProcessSqlCommand(transactionID, command); db->processSqlCommand(transactionID, command);
}); });
} }
std::shared_ptr<Database> SqfliteAuroraPlugin::databaseByPath(const std::string &path) std::shared_ptr<Database> SqfliteAuroraPlugin::databaseByPath(const std::string &path)
{ {
std::lock_guard<std::mutex> lock(this->mutex); std::lock_guard<std::mutex> lock(m_mutex);
if (!this->singletonDatabases.count(path)) if (!m_singleInstanceDatabases.count(path))
return nullptr; return nullptr;
return this->singletonDatabases.at(path); return m_singleInstanceDatabases.at(path);
} }
std::shared_ptr<Database> SqfliteAuroraPlugin::databaseByID(int64_t id) std::shared_ptr<Database> SqfliteAuroraPlugin::databaseByID(int64_t id)
{ {
std::lock_guard<std::mutex> lock(this->mutex); std::lock_guard<std::mutex> lock(m_mutex);
if (!this->databases.count(id)) if (!m_databases.count(id))
return nullptr; return nullptr;
return this->databases.at(id); return m_databases.at(id);
} }
void SqfliteAuroraPlugin::databaseRemove(std::shared_ptr<Database> db) void SqfliteAuroraPlugin::databaseRemove(std::shared_ptr<Database> db)
{ {
std::lock_guard<std::mutex> lock(this->mutex); std::lock_guard<std::mutex> lock(m_mutex);
if (db->IsSingleInstance()) if (db->isSingleInstance())
this->singletonDatabases.erase(db->Path()); m_singleInstanceDatabases.erase(db->path());
this->databases.erase(db->ID()); m_databases.erase(db->id());
} }
void SqfliteAuroraPlugin::databaseAdd(std::shared_ptr<Database> db) void SqfliteAuroraPlugin::databaseAdd(std::shared_ptr<Database> db)
{ {
std::lock_guard<std::mutex> lock(this->mutex); std::lock_guard<std::mutex> lock(m_mutex);
if (db->IsSingleInstance()) if (db->isSingleInstance())
this->singletonDatabases.emplace(db->Path(), db); m_singleInstanceDatabases.emplace(db->path(), db);
this->databases.emplace(db->ID(), db); m_databases.emplace(db->id(), db);
} }
void SqfliteAuroraPlugin::success(const MethodCall &call, const Encodable &result) void SqfliteAuroraPlugin::sendSuccess(const MethodCall &call, const Encodable &result)
{ {
call.SendSuccessResponse(result); call.SendSuccessResponse(result);
} }
void SqfliteAuroraPlugin::error(const MethodCall &call, void SqfliteAuroraPlugin::sendError(const MethodCall &call,
const std::string &error, const std::string &error,
const std::string &message, const std::string &message,
const std::string &desc, const std::string &desc,

28
packages/sqflite/sqflite_aurora/aurora/lib/utils.cpp

@ -0,0 +1,28 @@
/*
* Copyright (c) 2023. Open Mobile Platform LLC.
* License: Proprietary.
*/
#include <sqflite_aurora/utils.h>
namespace utils {
error::error(std::string message)
: m_message(std::move(message))
{}
utils::error error::none()
{
return {};
}
error::operator bool() const
{
return m_message.has_value();
}
const std::string &error::message() const
{
return m_message.value();
}
} /* namespace utils */
Loading…
Cancel
Save