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. 101
      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. 35
      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. 286
      packages/sqflite/sqflite_aurora/aurora/lib/database.cpp
  11. 34
      packages/sqflite/sqflite_aurora/aurora/lib/logger.cpp
  12. 410
      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)
add_library(${PLUGIN_NAME} SHARED
lib/asynq.cpp
lib/async_queue.cpp
lib/database.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)
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 <functional>
#include <mutex>
#include <thread>
#include <queue>
#include <thread>
#ifdef PLUGIN_IMPL
#define PLUGIN_EXPORT __attribute__((visibility("default")))
#else
#define PLUGIN_EXPORT
#endif
#include <sqflite_aurora/globals.h>
class PLUGIN_EXPORT AsyncQueue final
{
@ -26,7 +22,7 @@ public:
AsyncQueue();
~AsyncQueue();
void Push(const Task &task);
void push(const Task &task);
private:
void run();

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

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

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

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

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

@ -7,19 +7,14 @@
#include <flutter/plugin-interface.h>
#include <sqflite_aurora/asynq.h>
#include <sqflite_aurora/async_queue.h>
#include <sqflite_aurora/database.h>
#include <sqflite_aurora/globals.h>
#include <memory>
#include <mutex>
#include <unordered_map>
#ifdef PLUGIN_IMPL
#define PLUGIN_EXPORT __attribute__((visibility("default")))
#else
#define PLUGIN_EXPORT
#endif
class PLUGIN_EXPORT SqfliteAuroraPlugin final : public PluginInterface
{
public:
@ -49,23 +44,23 @@ private:
void databaseRemove(std::shared_ptr<Database> db);
void databaseAdd(std::shared_ptr<Database> db);
void success(const MethodCall &call, const Encodable &result = nullptr);
void error(const MethodCall &call,
const std::string &error,
const std::string &message,
const std::string &desc = "",
const Encodable &details = nullptr);
void sendSuccess(const MethodCall &call, const Encodable &result = nullptr);
void sendError(const MethodCall &call,
const std::string &error,
const std::string &message,
const std::string &desc = "",
const Encodable &details = nullptr);
Encodable::Map makeOpenResult(int64_t dbID, bool recovered, bool recoveredInTransaction);
private:
std::mutex mutex;
std::unordered_map<std::string, std::shared_ptr<Database>> singletonDatabases;
std::unordered_map<int64_t, std::shared_ptr<Database>> databases;
int64_t dbID = 0;
Logger logger;
bool queryAsMapList = false;
AsyncQueue asynq;
std::mutex m_mutex;
std::unordered_map<std::string, std::shared_ptr<Database>> m_singleInstanceDatabases;
std::unordered_map<int64_t, std::shared_ptr<Database>> m_databases;
int64_t m_dbID = 0;
Logger m_logger;
bool m_queryAsMapList = false;
AsyncQueue m_asyncQueue;
};
#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.
* License: Proprietary.
*/
#include <sqflite_aurora/asynq.h>
#include <sqflite_aurora/async_queue.h>
AsyncQueue::AsyncQueue()
: m_running(false)
@ -15,7 +15,7 @@ AsyncQueue::~AsyncQueue()
m_thread.join();
}
void AsyncQueue::Push(const Task &task)
void AsyncQueue::push(const Task &task)
{
if (!m_running) {
m_running = true;
@ -38,8 +38,8 @@ void AsyncQueue::run()
const auto task = m_tasks.front();
m_tasks.pop();
lock.unlock();
lock.unlock();
task();
}
}

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

@ -10,11 +10,13 @@
namespace {
void addError(Encodable::List &results, const std::string &error)
void addError(Encodable::List &results, const utils::error &error)
{
results.emplace_back(Encodable::Map{
{"error", Encodable::Map{{"message", error}}},
});
if (error) {
results.emplace_back(Encodable::Map{
{"error", Encodable::Map{{"message", error.message()}}},
});
}
}
template<typename T>
@ -25,72 +27,72 @@ void addResult(Encodable::List &results, const T &result)
} /* namespace */
Database::Database(int id, const std::string &path, bool singleton, const Logger &logger)
: id(id)
, path(path)
, isSingleInstance(singleton)
, logger(logger.LogLevel(), logger.Tag() + "-db-" + std::to_string(id))
, transactionID(0)
, currentTransactionID(TransactionID::None)
, cursorID(0)
, db(nullptr)
Database::Database(int id, const std::string &path, bool singleInstance, const Logger &logger)
: m_id(id)
, m_path(path)
, m_isSingleInstance(singleInstance)
, m_logger(logger.logLevel(), logger.tag() + "-db-" + std::to_string(id))
, m_transactionID(0)
, m_currentTransactionID(TransactionID::None)
, m_cursorID(0)
, m_db(nullptr)
{}
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)
return error;
int result_code = sqlite3_open_v2(this->path.c_str(),
&this->db,
int result_code = sqlite3_open_v2(m_path.c_str(),
&m_db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
nullptr);
if (result_code != SQLITE_OK)
return this->currentErrorMessage();
return utils::error(currentErrorMessage());
this->isReadOnly = false;
return std::nullopt;
m_isReadOnly = false;
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)
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)
return this->currentErrorMessage();
return utils::error(currentErrorMessage());
this->isReadOnly = true;
return std::nullopt;
m_isReadOnly = true;
return utils::error::none();
}
std::optional<std::string> Database::Close()
utils::error Database::close()
{
if (sqlite3_close_v2(this->db) != SQLITE_OK)
return this->currentErrorMessage();
if (sqlite3_close_v2(m_db) != SQLITE_OK)
return utils::error(currentErrorMessage());
this->db = nullptr;
this->pendingSqlCallbacks = {};
m_db = nullptr;
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;
if (sqlite3_prepare_v2(this->db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK)
return this->currentErrorMessage();
if (sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK)
return utils::error(currentErrorMessage());
const auto error = this->bindStmtArgs(stmt, args);
const auto error = bindStmtArgs(stmt, args);
if (error) {
sqlite3_finalize(stmt);
@ -107,23 +109,23 @@ std::optional<std::string> Database::Execute(const std::string &sql, const Encod
break;
sqlite3_finalize(stmt);
return this->currentErrorMessage();
return utils::error(currentErrorMessage());
}
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,
Encodable::Map &result)
{
sqlite3_stmt *stmt = nullptr;
if (sqlite3_prepare_v2(this->db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK)
return this->currentErrorMessage();
if (sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK)
return utils::error(currentErrorMessage());
const auto error = this->bindStmtArgs(stmt, args);
const auto error = bindStmtArgs(stmt, args);
if (error) {
sqlite3_finalize(stmt);
@ -184,206 +186,206 @@ std::optional<std::string> Database::Query(const std::string &sql,
break;
sqlite3_finalize(stmt);
return this->currentErrorMessage();
return utils::error(currentErrorMessage());
}
result = Encodable::Map{{"columns", columns}, {"rows", rows}};
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,
int64_t pageSize,
Encodable::Map &result)
{
sqlite3_stmt *stmt = nullptr;
if (sqlite3_prepare_v2(this->db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK)
return this->currentErrorMessage();
if (sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK)
return utils::error(currentErrorMessage());
const auto error = this->bindStmtArgs(stmt, args);
const auto error = bindStmtArgs(stmt, args);
if (error)
return error;
this->cursorID += 1;
this->cursors[cursorID] = Cursor{this->cursorID, stmt, pageSize};
m_cursorID += 1;
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,
Encodable::Map &result)
{
this->logger.verb() << "querying cursor next (ID=" << cursorID << "; CANCEL=" << cancel << ")"
<< std::endl;
m_logger.verb() << "querying cursor next (ID=" << cursorID << "; CANCEL=" << cancel << ")"
<< std::endl;
if (!this->cursors.count(cursorID))
return "cursor not found";
if (!m_cursors.count(cursorID))
return utils::error("cursor not found");
const Cursor &cursor = this->cursors[cursorID];
const Cursor &cursor = m_cursors[cursorID];
if (cancel) {
this->closeCursor(cursor);
return std::nullopt;
closeCursor(cursor);
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,
int &insertID)
{
if (this->isReadOnly)
return "database is readonly";
if (m_isReadOnly)
return utils::error("database is readonly");
const auto error = this->Execute(sql, args);
const auto error = execute(sql, args);
if (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) {
insertID = 0;
return std::nullopt;
return utils::error::none();
}
insertID = sqlite3_last_insert_rowid(this->db);
this->logger.sql() << "last inserted row id: " << insertID << std::endl;
insertID = sqlite3_last_insert_rowid(m_db);
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,
int &updated)
{
if (this->isReadOnly)
return "database is readonly";
if (m_isReadOnly)
return utils::error("database is readonly");
const auto error = this->Execute(sql, args);
const auto error = execute(sql, args);
if (error)
return error;
updated = sqlite3_changes(this->db);
this->logger.sql() << "rows updated: " << updated << std::endl;
updated = sqlite3_changes(m_db);
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();
return;
}
if (transactionID == this->currentTransactionID || transactionID == TransactionID::Force) {
if (transactionID == m_currentTransactionID || transactionID == TransactionID::Force) {
callback();
if (this->currentTransactionID == TransactionID::None) {
while (!this->pendingSqlCallbacks.empty() && this->IsOpen()) {
const auto &pendingCallback = this->pendingSqlCallbacks.front();
if (m_currentTransactionID == TransactionID::None) {
while (!m_pendingSqlCallbacks.empty() && isOpen()) {
const auto &pendingCallback = m_pendingSqlCallbacks.front();
pendingCallback();
this->pendingSqlCallbacks.pop();
m_pendingSqlCallbacks.pop();
}
}
return;
}
this->pendingSqlCallbacks.push(callback);
m_pendingSqlCallbacks.push(callback);
}
void Database::EnterInTransaction()
void Database::enterInTransaction()
{
this->transactionID += 1;
this->currentTransactionID = this->transactionID;
m_transactionID += 1;
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()
{
const auto message = sqlite3_errmsg(this->db);
const auto code = sqlite3_extended_errcode(this->db);
const auto message = sqlite3_errmsg(m_db);
const auto code = sqlite3_extended_errcode(m_db);
return std::string(message) + " (" + std::to_string(code) + ")";
}
std::optional<std::string> Database::createParentDir()
utils::error Database::createParentDir()
{
if (this->IsInMemory())
return std::nullopt;
if (isInMemory())
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))
return std::nullopt;
return utils::error::none();
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;
@ -451,12 +453,12 @@ std::optional<std::string> Database::bindStmtArgs(sqlite3_stmt *stmt, const Enco
for (const auto &entry : arg.GetList()) {
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();
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));
}
@ -467,25 +469,25 @@ std::optional<std::string> Database::bindStmtArgs(sqlite3_stmt *stmt, const Enco
container.size(),
SQLITE_TRANSIENT);
} else {
return "statement parameter has invalid type";
return utils::error("statement parameter has invalid type");
}
if (result != SQLITE_OK)
return this->currentErrorMessage();
return utils::error(currentErrorMessage());
}
this->logger.sql() << sqlite3_expanded_sql(stmt) << std::endl;
return std::nullopt;
m_logger.sql() << sqlite3_expanded_sql(stmt) << std::endl;
return utils::error::none();
}
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);
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;
@ -540,12 +542,12 @@ std::optional<std::string> Database::resultFromCursor(const Cursor &cursor, Enco
}
if (status == SQLITE_DONE) {
this->closeCursor(cursor);
closeCursor(cursor);
break;
}
this->closeCursor(cursor);
return this->currentErrorMessage();
closeCursor(cursor);
return utils::error(currentErrorMessage());
}
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)
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,
Encodable::List &results)
{
@ -565,13 +567,13 @@ std::optional<std::string> Database::Batch(const std::vector<Operation> &operati
if (method == METHOD_INSERT) {
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 (!continueOnError)
return error;
addError(results, *error);
addError(results, error);
continue;
}
@ -584,13 +586,13 @@ std::optional<std::string> Database::Batch(const std::vector<Operation> &operati
}
if (method == METHOD_EXECUTE) {
const auto error = this->Execute(operation.sql, operation.arguments);
const auto error = execute(operation.sql, operation.arguments);
if (error) {
if (!continueOnError)
return error;
addError(results, *error);
addError(results, error);
continue;
}
@ -600,13 +602,13 @@ std::optional<std::string> Database::Batch(const std::vector<Operation> &operati
if (method == METHOD_QUERY) {
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 (!continueOnError)
return error;
addError(results, *error);
addError(results, error);
continue;
}
@ -616,13 +618,13 @@ std::optional<std::string> Database::Batch(const std::vector<Operation> &operati
if (method == METHOD_UPDATE) {
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 (!continueOnError)
return error;
addError(results, *error);
addError(results, error);
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>
Logger::Logger(Level level, const std::string &tag)
: level(level)
, tag(tag)
, devnull(0)
: m_level(level)
, m_tag(tag)
, 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()
{
if (this->level >= Level::Verbose)
return loginfo << (this->tag.empty() ? "" : "[" + this->tag + "] ");
if (m_level >= Level::Verbose)
return loginfo << (m_tag.empty() ? "" : "[" + m_tag + "] ");
return this->devnull;
return m_devnull;
}
std::ostream &Logger::sql()
{
if (this->level >= Level::Sql)
return loginfo << (this->tag.empty() ? "" : "[" + this->tag + "] ");
if (m_level >= Level::Sql)
return loginfo << (m_tag.empty() ? "" : "[" + m_tag + "] ");
return this->devnull;
return m_devnull;
}

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

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