Skip to content

Commit ae61431

Browse files
committed
Added async queries
1 parent 0ae4cd5 commit ae61431

5 files changed

Lines changed: 136 additions & 14 deletions

File tree

src/connection.cpp

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include "res.h"
55

66
using namespace intercept::client;
7-
7+
extern auto_array<ref<GameDataDBAsyncResult>> asyncWork;
88

99
class GameDataDBConnection : public game_data {
1010

@@ -17,7 +17,7 @@ class GameDataDBConnection : public game_data {
1717
bool get_as_bool() const override { return true; }
1818
float get_as_number() const override { return 0.f; }
1919
const r_string& get_as_string() const override { static r_string nm("stuff"sv); return nm; }
20-
game_data* copy() const override { return new GameDataDBConnection(*this); } //#TODO make sure this works
20+
game_data* copy() const override { return new GameDataDBConnection(*this); }
2121
r_string to_string() const override {
2222
if (!session) return r_string("<no session>"sv);
2323
if (!session->connected()) return r_string("<not connected>"sv);
@@ -101,6 +101,34 @@ game_value Connection::cmd_query(uintptr_t, game_value_parameter con, game_value
101101
return gd_res;
102102
}
103103

104+
game_value Connection::cmd_queryAsync(uintptr_t, game_value_parameter con, game_value_parameter qu) {
105+
106+
auto session = con.get_as<GameDataDBConnection>()->session;
107+
auto query = qu.get_as<GameDataDBQuery>();
108+
109+
auto gd_res = new GameDataDBAsyncResult();
110+
gd_res->data = std::make_shared<GameDataDBAsyncResult::dataT>();
111+
gd_res->data->res =
112+
std::async([session, stmt = query->queryString, boundV = query->boundValues]() -> mariadb::result_set_ref
113+
{
114+
auto statement = session->create_statement(stmt);
115+
116+
uint32_t idx = 0;
117+
for (auto& it : boundV) {
118+
119+
switch (it.type_enum()) {
120+
case game_data_type::SCALAR: statement->set_float(idx++, static_cast<float>(it)); break;
121+
case game_data_type::BOOL: statement->set_boolean(idx++, static_cast<bool>(it)); break;
122+
case game_data_type::STRING: statement->set_string(idx++, static_cast<r_string>(it)); break;
123+
default:;
124+
}
125+
}
126+
return statement->query();
127+
});
128+
asyncWork.emplace_back(gd_res);
129+
return gd_res;
130+
}
131+
104132
void Connection::initCommands() {
105133

106134
auto dbType = host::register_sqf_type("DBCON"sv, "databaseConnection"sv, "TODO"sv, "databaseConnection"sv, createGameDataDBConnection);
@@ -109,5 +137,6 @@ void Connection::initCommands() {
109137

110138

111139
handle_cmd_createConnection = host::register_sqf_command("db_createConnection", "TODO", Connection::cmd_createConnectionArray, GameDataDBConnection_typeE, game_data_type::ARRAY);
112-
handle_cmd_query = host::register_sqf_command("db_query", "TODO", Connection::cmd_query, Query::GameDataDBQuery_typeE, GameDataDBConnection_typeE, Query::GameDataDBQuery_typeE);
140+
handle_cmd_query = host::register_sqf_command("db_query", "TODO", Connection::cmd_query, Result::GameDataDBResult_typeE, GameDataDBConnection_typeE, Query::GameDataDBQuery_typeE);
141+
handle_cmd_queryAsync = host::register_sqf_command("db_queryAsync", "TODO", Connection::cmd_queryAsync, Result::GameDataDBAsyncResult_typeE, GameDataDBConnection_typeE, Query::GameDataDBQuery_typeE);
113142
}

src/connection.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ class Connection {
99
public:
1010

1111
static game_value cmd_createConnectionArray(uintptr_t, game_value_parameter right);
12-
static game_value cmd_query(uintptr_t, game_value_parameter con, game_value_parameter qu);
12+
static game_value cmd_query(uintptr_t, game_value_parameter con, game_value_parameter qu);
13+
static game_value cmd_queryAsync(uintptr_t, game_value_parameter con, game_value_parameter qu);
1314

1415

1516

@@ -20,5 +21,6 @@ class Connection {
2021

2122

2223
static inline types::registered_sqf_function handle_cmd_createConnection;
23-
static inline types::registered_sqf_function handle_cmd_query;
24+
static inline types::registered_sqf_function handle_cmd_query;
25+
static inline types::registered_sqf_function handle_cmd_queryAsync;
2426
};

src/main.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
int intercept::api_version() { //This is required for the plugin to work.
88
return 1;
99
}
10-
10+
auto_array<ref<GameDataDBAsyncResult>> asyncWork;
1111
void intercept::register_interfaces() {
1212

1313
}
@@ -32,6 +32,28 @@ void intercept::pre_init() {
3232
intercept::sqf::system_chat("Intercept database has been loaded");
3333
}
3434

35+
void intercept::on_frame() {
36+
37+
std::vector<ref<GameDataDBAsyncResult>> done;
38+
39+
40+
auto p = std::stable_partition(asyncWork.begin(), asyncWork.end(),
41+
[&](const auto& x) { return x->data->res.wait_for(std::chrono::nanoseconds(0)) == std::future_status::ready; });
42+
// range insert with move
43+
done.insert(done.end(), std::make_move_iterator(p),
44+
std::make_move_iterator(asyncWork.end()));
45+
// erase the moved-from elements.
46+
asyncWork.erase(p, asyncWork.end());
47+
48+
for (auto& it : done) {
49+
auto gd_res = new GameDataDBResult();
50+
gd_res->res = it->data->res.get();
51+
52+
sqf::call(it->data->callback, { gd_res, it->data->callbackArgs });
53+
}
54+
}
55+
56+
3557
/*
3658
3759
DB_Connection = db_createConnection [ip, port, username, password, database];

src/res.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ game_data* createGameDataDBResult(param_archive* ar) {
1111
return x;
1212
}
1313

14+
game_data* createGameDataDBAsyncResult(param_archive* ar) {
15+
auto x = new GameDataDBAsyncResult();
16+
if (ar)
17+
x->serialize(*ar);
18+
return x;
19+
}
1420

1521
game_value Result::cmd_affectedRows(uintptr_t, game_value_parameter right) {
1622
auto& res = right.get_as<GameDataDBResult>()->res;
@@ -61,16 +67,28 @@ game_value Result::cmd_toArray(uintptr_t, game_value_parameter right) {
6167
return result;
6268
}
6369

70+
game_value Result::cmd_bindCallback(uintptr_t, game_value_parameter left, game_value_parameter right) {
71+
auto& res = left.get_as<GameDataDBAsyncResult>();
72+
73+
res->data->callback = right[0];
74+
res->data->callbackArgs = right[1]; //#TODO call directly if result is ready
75+
return {};
76+
}
77+
6478
void ::Result::initCommands() {
6579

66-
auto dbType = host::register_sqf_type("DBQUERRY"sv, "databaseQuery"sv, "TODO"sv, "databaseQuery"sv, createGameDataDBResult);
80+
auto dbType = host::register_sqf_type("DBRES"sv, "databaseResult"sv, "TODO"sv, "databaseResult"sv, createGameDataDBResult);
6781
GameDataDBResult_typeE = dbType.first;
6882
GameDataDBResult_type = dbType.second;
6983

84+
auto dbTypeA = host::register_sqf_type("DBRESASYNC"sv, "databaseResultAsync"sv, "TODO"sv, "databaseResultAsync"sv, createGameDataDBResult);
85+
GameDataDBAsyncResult_typeE = dbTypeA.first;
86+
GameDataDBAsyncResult_type = dbTypeA.second;
7087

7188
handle_cmd_affectedRows = client::host::register_sqf_command("db_resultAffectedRows", "TODO", Result::cmd_affectedRows, game_data_type::SCALAR, GameDataDBResult_typeE);
7289
handle_cmd_lastInsertId = client::host::register_sqf_command("db_resultLastInsertId", "TODO", Result::cmd_lastInsertId, game_data_type::SCALAR, GameDataDBResult_typeE);
7390
handle_cmd_toArray = client::host::register_sqf_command("db_resultToArray", "TODO", Result::cmd_toArray, game_data_type::ARRAY, GameDataDBResult_typeE);
91+
handle_cmd_bindCallback = client::host::register_sqf_command("db_bindCallback", "TODO", Result::cmd_bindCallback, game_data_type::NOTHING, GameDataDBAsyncResult_typeE, game_data_type::ARRAY);
7492

7593

7694
}

src/res.h

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22
#include <intercept.hpp>
33
#include <mariadb++/result_set.hpp>
4+
#include <future>
45
using namespace intercept;
56
using namespace intercept::types;
67

@@ -11,20 +12,22 @@ class Result {
1112

1213
static game_value cmd_affectedRows(uintptr_t, game_value_parameter right);
1314
static game_value cmd_lastInsertId(uintptr_t, game_value_parameter right);
14-
static game_value cmd_toArray(uintptr_t, game_value_parameter right);
15-
16-
17-
15+
static game_value cmd_toArray(uintptr_t, game_value_parameter right);
16+
static game_value cmd_bindCallback(uintptr_t, game_value_parameter left, game_value_parameter right);
1817

1918
static void initCommands();
2019
static inline sqf_script_type GameDataDBResult_type;
2120
static inline game_data_type GameDataDBResult_typeE;
21+
static inline sqf_script_type GameDataDBAsyncResult_type;
22+
static inline game_data_type GameDataDBAsyncResult_typeE;
2223

2324
static inline types::registered_sqf_function handle_cmd_affectedRows;
2425
static inline types::registered_sqf_function handle_cmd_lastInsertId;
25-
static inline types::registered_sqf_function handle_cmd_toArray;
26+
static inline types::registered_sqf_function handle_cmd_toArray;
27+
static inline types::registered_sqf_function handle_cmd_bindCallback;
2628
};
2729

30+
2831
class GameDataDBResult : public game_data {
2932

3033
public:
@@ -36,10 +39,10 @@ class GameDataDBResult : public game_data {
3639
bool get_as_bool() const override { return true; }
3740
float get_as_number() const override { return 0.f; }
3841
const r_string& get_as_string() const override { static r_string nm("TODO"sv); return nm; }
39-
game_data* copy() const override { return new GameDataDBResult(*this); } //#TODO can't do that dave
42+
game_data* copy() const override { return new GameDataDBResult(*this); }
4043
r_string to_string() const override { return r_string("TODO"sv); }
4144
//virtual bool equals(const game_data*) const override; //#TODO isEqualTo on hashMaps would be quite nice I guess?
42-
const char* type_as_string() const override { return "databaseQuery"; }
45+
const char* type_as_string() const override { return "databaseResult"; }
4346
bool is_nil() const override { return false; }
4447
bool can_serialize() override { return true; }//Setting this to false causes a fail in scheduled and global vars
4548

@@ -63,4 +66,52 @@ class GameDataDBResult : public game_data {
6366
}
6467

6568
mariadb::result_set_ref res;
69+
};
70+
71+
class GameDataDBAsyncResult : public game_data {
72+
73+
public:
74+
GameDataDBAsyncResult() {}
75+
void lastRefDeleted() const override { delete this; }
76+
const sqf_script_type& type() const override { return Result::GameDataDBAsyncResult_type; }
77+
~GameDataDBAsyncResult() override {};
78+
79+
bool get_as_bool() const override { return true; }
80+
float get_as_number() const override { return 0.f; }
81+
const r_string& get_as_string() const override { static r_string nm("TODO"sv); return nm; }
82+
game_data* copy() const override {
83+
return new GameDataDBAsyncResult(*this);
84+
} //#TODO can't do that dave
85+
r_string to_string() const override { return r_string("TODO"sv); }
86+
//virtual bool equals(const game_data*) const override; //#TODO isEqualTo on hashMaps would be quite nice I guess?
87+
const char* type_as_string() const override { return "databaseResultAsync"; }
88+
bool is_nil() const override { return false; }
89+
bool can_serialize() override { return false; }//Setting this to false causes a fail in scheduled and global vars
90+
91+
serialization_return serialize(param_archive& ar) override {
92+
game_data::serialize(ar);
93+
//size_t entryCount;
94+
//if (ar._isExporting) entryCount = map.size();
95+
//ar.serialize("entryCount"sv, entryCount, 1);
96+
//#TODO add array serialization functions
97+
//ar._p1->add_array_entry()
98+
//if (!ar._isExporting) {
99+
//
100+
// for (int i = 0; i < entryCount; ++i) {
101+
// s
102+
// }
103+
//
104+
//
105+
//
106+
//}
107+
return serialization_return::no_error;
108+
}
109+
struct dataT {
110+
std::future<mariadb::result_set_ref> res;
111+
game_value callback;
112+
game_value callbackArgs;
113+
};
114+
std::shared_ptr<dataT> data;
115+
116+
66117
};

0 commit comments

Comments
 (0)