Skip to content

Commit dd5dcaa

Browse files
authored
Release v1.2.0 (#20)
* Added Windows support. * Added Apple support. * Added compile-time warnings setup. * Added `DiscardAll` and `FetchAll` in C++. * Fixed type checking in C++ `ConstValue::ValueMap` method. * Fixed pull error handling in the C++ `Client::Execute` method. * Fixed various compile-time warnings. * Fixed `mg_session_params_get_client_name` by renaming it to `mg_session_params_get_user_agent` (the one implemented in `src/mgclient.c`). * Add advanced C++ example.
1 parent de9f60a commit dd5dcaa

File tree

10 files changed

+201
-49
lines changed

10 files changed

+201
-49
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
run: |
3232
mkdir build
3333
cd build
34-
cmake -DOPENSSL_ROOT_DIR=/usr/local/Cellar/openssl@1.1/1.1.1h -DCMAKE_INSTALL_PREFIX=/usr/local -DBUILD_TESTING=ON -DBUILD_TESTING_INTEGRATION=ON -DC_WARNINGS_AS_ERRORS=ON -DCPP_WARNINGS_AS_ERRORS=ON ..
34+
cmake -DOPENSSL_ROOT_DIR=/usr/local/Cellar/openssl@1.1/1.1.1i -DCMAKE_INSTALL_PREFIX=/usr/local -DBUILD_TESTING=ON -DBUILD_TESTING_INTEGRATION=ON -DC_WARNINGS_AS_ERRORS=ON -DCPP_WARNINGS_AS_ERRORS=ON ..
3535
make
3636
ctest -E "example|integration"
3737
sudo make install

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
cmake_minimum_required(VERSION 3.8)
1616

17-
project(mgclient VERSION 1.1.0)
17+
project(mgclient VERSION 1.2.0)
1818
# Minor version increase can also mean ABI incompatibility with previous
1919
# versions. IMPORTANT: Take care of the SO version manually.
2020
set(mgclient_SOVERSION 2)

examples/advanced.cpp

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#include <iostream>
2+
#include <numeric>
3+
4+
#include "mgclient.hpp"
5+
6+
void ClearDatabaseData(mg::Client *client) {
7+
if (!client->Execute("MATCH (n) DETACH DELETE n;")) {
8+
std::cerr << "Failed to delete all data from the database." << std::endl;
9+
std::exit(1);
10+
}
11+
client->DiscardAll();
12+
}
13+
14+
int main(int argc, char *argv[]) {
15+
if (argc != 3) {
16+
std::cerr << "Usage: " << argv[0] << " [host] [port]\n";
17+
std::exit(1);
18+
}
19+
20+
mg::Client::Init();
21+
22+
{
23+
mg::Client::Params params;
24+
params.host = argv[1];
25+
params.port = static_cast<uint16_t>(atoi(argv[2]));
26+
auto client = mg::Client::Connect(params);
27+
if (!client) {
28+
std::cerr << "Failed to connect." << std::endl;
29+
return 1;
30+
}
31+
32+
ClearDatabaseData(client.get());
33+
34+
if (!client->Execute("CREATE INDEX ON :Person(id);")) {
35+
std::cerr << "Failed to create an index." << std::endl;
36+
return 1;
37+
}
38+
client->DiscardAll();
39+
40+
if (!client->Execute(
41+
"CREATE (:Person:Entrepreneur {id: 0, age: 40, name: 'John', "
42+
"isStudent: false, score: 5.0});")) {
43+
std::cerr << "Failed to add data." << std::endl;
44+
return 1;
45+
}
46+
client->DiscardAll();
47+
48+
if (!client->Execute("MATCH (n) RETURN n;")) {
49+
std::cerr << "Failed to read data." << std::endl;
50+
return 1;
51+
}
52+
if (const auto maybe_data = client->FetchAll()) {
53+
const auto data = *maybe_data;
54+
std::cout << "Number of results: " << data.size() << std::endl;
55+
}
56+
57+
if (!client->Execute("MATCH (n) RETURN n;")) {
58+
std::cerr << "Failed to read data." << std::endl;
59+
return 1;
60+
}
61+
while (const auto maybe_result = client->FetchOne()) {
62+
const auto result = *maybe_result;
63+
if (result.size() < 1) {
64+
continue;
65+
}
66+
const auto value = result[0];
67+
if (value.type() == mg::Value::Type::Node) {
68+
const auto node = value.ValueNode();
69+
auto labels = node.labels();
70+
std::string labels_str = std::accumulate(
71+
labels.begin(), labels.end(), std::string(""),
72+
[](const std::string &acc, const std::string_view value) {
73+
return acc + ":" + std::string(value);
74+
});
75+
const auto props = node.properties();
76+
std::string props_str =
77+
std::accumulate(
78+
props.begin(), props.end(), std::string("{"),
79+
[](const std::string &acc, const auto &key_value) {
80+
const auto &[key, value] = key_value;
81+
std::string value_str;
82+
if (value.type() == mg::Value::Type::Int) {
83+
value_str = std::to_string(value.ValueInt());
84+
} else if (value.type() == mg::Value::Type::String) {
85+
value_str = value.ValueString();
86+
} else if (value.type() == mg::Value::Type::Bool) {
87+
value_str = std::to_string(value.ValueBool());
88+
} else if (value.type() == mg::Value::Type::Double) {
89+
value_str = std::to_string(value.ValueDouble());
90+
} else {
91+
std::cerr
92+
<< "Uncovered converstion from data type to a string"
93+
<< std::endl;
94+
std::exit(1);
95+
}
96+
return acc + " " + std::string(key) + ": " + value_str;
97+
}) +
98+
" }";
99+
std::cout << labels_str << " " << props_str << std::endl;
100+
}
101+
}
102+
103+
ClearDatabaseData(client.get());
104+
}
105+
106+
mg::Client::Finalize();
107+
108+
return 0;
109+
}

include/mgclient.h

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -739,8 +739,7 @@ MGCLIENT_EXPORT uint32_t mg_map_size(const mg_map *map);
739739
/// Retrieves the key at position \p pos in map \p map.
740740
///
741741
/// \return A pointer to required key. If \p pos is outside of map bounds, \c
742-
/// NULL
743-
/// is returned.
742+
/// NULL is returned.
744743
MGCLIENT_EXPORT const mg_string *mg_map_key_at(const mg_map *, uint32_t pos);
745744

746745
/// Retrieves the value at position \p pos in map \p map.
@@ -1036,7 +1035,7 @@ MGCLIENT_EXPORT void mg_point_3d_destroy(mg_point_3d *point_3d);
10361035
#define MG_SESSION_BAD 2
10371036

10381037
/// Marks a \ref mg_session which is currently fetching result of a query.
1039-
/// Results can be pulled using \ref mg_session_fetch.
1038+
/// Results can be fetched using \ref mg_session_fetch.
10401039
#define MG_SESSION_FETCHING 3
10411040

10421041
/// Success code.
@@ -1233,7 +1232,7 @@ MGCLIENT_EXPORT const char *mg_session_params_get_username(
12331232
const mg_session_params *);
12341233
MGCLIENT_EXPORT const char *mg_session_params_get_password(
12351234
const mg_session_params *);
1236-
MGCLIENT_EXPORT const char *mg_session_params_get_client_name(
1235+
MGCLIENT_EXPORT const char *mg_session_params_get_user_agent(
12371236
const mg_session_params *);
12381237
MGCLIENT_EXPORT enum mg_sslmode mg_session_params_get_sslmode(
12391238
const mg_session_params *);
@@ -1287,18 +1286,19 @@ typedef struct mg_result mg_result;
12871286
/// next query.
12881287
///
12891288
/// \param session A \ref mg_session to be used for query
1290-
/// execution. \param query Query string. \param params A \ref
1291-
/// mg_map containing query parameters. NULL can be
1292-
/// supplied instead of an empty parameter map.
1289+
/// execution.
1290+
/// \param query Query string.
1291+
/// \param params A \ref mg_map containing query parameters. NULL
1292+
/// can be supplied instead of an empty parameter
1293+
/// map.
12931294
/// \param columns Names of the columns output by the query
1294-
/// execution will be
1295-
/// stored in here. This is the same as the value
1295+
/// execution will be stored in here. This is the
1296+
/// same as the value
12961297
/// obtained by \ref mg_result_columns on a pulled
12971298
/// \ref mg_result. NULL can be supplied if we're
12981299
/// not interested in the columns names.
1299-
///
13001300
/// \param extra_run_information A \ref mg_map containing extra information for
1301-
/// running the statement.
1301+
/// running the statement.
13021302
/// It can contain the following information:
13031303
/// - bookmarks - list of strings containing some
13041304
/// kind of bookmark identification
@@ -1316,9 +1316,9 @@ typedef struct mg_result mg_result;
13161316
/// takes place. If no `db` is sent or empty
13171317
/// string it implies that it is the default
13181318
/// database.
1319-
/// \param qid QID for the statement will be stored in here if
1320-
/// an Explicit transaction was started. \return Returns 0 if query was
1321-
/// submitted for execution successfuly.
1319+
/// \param qid QID for the statement will be stored in here
1320+
/// if an Explicit transaction was started.
1321+
/// \return Returns 0 if query was submitted for execution successfuly.
13221322
/// Otherwise, a non-zero error code is returned.
13231323
MGCLIENT_EXPORT int mg_session_run(mg_session *session, const char *query,
13241324
const mg_map *params,
@@ -1385,23 +1385,24 @@ MGCLIENT_EXPORT int mg_session_rollback_transaction(mg_session *session,
13851385
/// \return On success, 0 or 1 is returned. Exit code 1 means that a new result
13861386
/// row was obtained and stored in \p result and its contents may be
13871387
/// accessed using \ref mg_result_row. Exit code 0 means that there are
1388-
/// now more result rows and that the query execution summary was stored
1388+
/// no more result rows and that the query execution summary was stored
13891389
/// in \p result. Its contents may be accessed using \ref
13901390
/// mg_result_summary. On failure, a non-zero exit code is returned.
13911391
MGCLIENT_EXPORT int mg_session_fetch(mg_session *session, mg_result **result);
13921392

13931393
/// Tries to pull results of a statement.
13941394
///
13951395
/// \param session A \ref mg_session from which the results should be
1396-
/// pulled. \param pull_information A \ref mg_map that contains extra
1397-
/// information for pulling the results.
1396+
/// pulled.
1397+
/// \param pull_information A \ref mg_map that contains extra information for
1398+
/// pulling the results.
13981399
/// It can contain the following information:
1399-
/// - n - how many records to fetch. `n=-1` will fetch
1400-
/// all records.
1401-
/// - qid - query identification, specifies the result
1402-
/// from which statement the results should be pulled .
1403-
/// `qid=-1` denotes the last executed statement. This
1404-
/// is only for Explicit transactions.
1400+
/// - n - how many records to fetch. `n=-1` will fetch
1401+
/// all records.
1402+
/// - qid - query identification, specifies the result
1403+
/// from which statement the results should be pulled.
1404+
/// `qid=-1` denotes the last executed statement. This
1405+
/// is only for Explicit transactions.
14051406
/// \return Returns 0 if the result was pulled successfuly.
14061407
/// Otherwise, a non-zero error code is returned.
14071408
MGCLIENT_EXPORT int mg_session_pull(mg_session *session,

include/mgclient.hpp

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@
1717
#include <memory>
1818
#include <optional>
1919

20-
#include "mgclient.h"
21-
2220
#include "mgclient-value.hpp"
21+
#include "mgclient.h"
2322

2423
namespace mg {
2524

@@ -28,12 +27,12 @@ namespace mg {
2827
class Client {
2928
public:
3029
struct Params {
31-
std::string host;
32-
uint16_t port;
33-
std::string username;
34-
std::string password;
35-
bool use_ssl;
36-
std::string user_agent;
30+
std::string host = "127.0.0.1";
31+
uint16_t port = 7687;
32+
std::string username = "";
33+
std::string password = "";
34+
bool use_ssl = false;
35+
std::string user_agent = "mgclient++/" + std::string(mg_client_version());
3736
};
3837

3938
Client(const Client &) = delete;
@@ -61,7 +60,8 @@ class Client {
6160
/// \note
6261
/// After executing the statement, the method is blocked until all incoming
6362
/// data (execution results) are handled, i.e. until `FetchOne` method returns
64-
/// `std::nullopt`.
63+
/// `std::nullopt`. Even if the result set is empty, the fetching has to be
64+
/// done/finished to be able to execute another statement.
6565
bool Execute(const std::string &statement);
6666

6767
/// \brief Executes the given Cypher `statement`, supplied with additional
@@ -79,6 +79,12 @@ class Client {
7979
/// If there is nothing to fetch, `std::nullopt` is returned.
8080
std::optional<std::vector<Value>> FetchOne();
8181

82+
/// \brief Fetches all results and discards them.
83+
void DiscardAll();
84+
85+
/// \brief Fetches all results.
86+
std::optional<std::vector<std::vector<Value>>> FetchAll();
87+
8288
/// \brief Start a transaction.
8389
/// \return true when the transaction was successfully started, false
8490
/// otherwise.
@@ -189,6 +195,19 @@ inline std::optional<std::vector<Value>> Client::FetchOne() {
189195
return values;
190196
}
191197

198+
inline void Client::DiscardAll() {
199+
while (FetchOne())
200+
;
201+
}
202+
203+
inline std::optional<std::vector<std::vector<Value>>> Client::FetchAll() {
204+
std::vector<std::vector<Value>> data;
205+
while (auto maybe_result = FetchOne()) {
206+
data.emplace_back(std::move(*maybe_result));
207+
}
208+
return data;
209+
}
210+
192211
inline bool Client::BeginTransaction() {
193212
return mg_session_begin_transaction(session_, nullptr) == 0;
194213
}

src/mgclient.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ mg_session_params *mg_session_params_make() {
6060
params->port = 0;
6161
params->username = NULL;
6262
params->password = NULL;
63-
params->user_agent = MG_USER_AGENT_DEFAULT;
63+
params->user_agent = MG_USER_AGENT;
6464
params->sslmode = MG_SSLMODE_DISABLE;
6565
params->sslcert = NULL;
6666
params->sslkey = NULL;
@@ -767,15 +767,15 @@ int mg_session_run(mg_session *session, const char *query, const mg_map *params,
767767

768768
int mg_session_pull(mg_session *session, const mg_map *pull_information) {
769769
if (session->status == MG_SESSION_BAD) {
770-
mg_session_set_error(session, "bad session");
770+
mg_session_set_error(session, "called pull while bad session");
771771
return MG_ERROR_BAD_CALL;
772772
}
773773
if (session->status == MG_SESSION_READY) {
774-
mg_session_set_error(session, "not executing a query");
774+
mg_session_set_error(session, "called pull while not executing a query");
775775
return MG_ERROR_BAD_CALL;
776776
}
777777
if (session->status == MG_SESSION_FETCHING) {
778-
mg_session_set_error(session, "fetching results from a query");
778+
mg_session_set_error(session, "called pull while still fetching data");
779779
return MG_ERROR_BAD_CALL;
780780
}
781781

@@ -805,15 +805,15 @@ int mg_session_pull(mg_session *session, const mg_map *pull_information) {
805805

806806
int mg_session_fetch(mg_session *session, mg_result **result) {
807807
if (session->status == MG_SESSION_BAD) {
808-
mg_session_set_error(session, "bad session");
808+
mg_session_set_error(session, "called fetch while bad session");
809809
return MG_ERROR_BAD_CALL;
810810
}
811811
if (session->status == MG_SESSION_READY) {
812-
mg_session_set_error(session, "not executing a query");
812+
mg_session_set_error(session, "called fetch while not executing a query");
813813
return MG_ERROR_BAD_CALL;
814814
}
815815
if (session->status == MG_SESSION_EXECUTING) {
816-
mg_session_set_error(session, "results not pulled");
816+
mg_session_set_error(session, "called fetch without pulling results");
817817
return MG_ERROR_BAD_CALL;
818818
}
819819
assert(session->status == MG_SESSION_FETCHING);
@@ -1061,13 +1061,19 @@ const mg_list *mg_result_columns(const mg_result *result) {
10611061
}
10621062

10631063
const mg_list *mg_result_row(const mg_result *result) {
1064+
if (!result->message) {
1065+
return NULL;
1066+
}
10641067
if (result->message->type != MG_MESSAGE_TYPE_RECORD) {
10651068
return NULL;
10661069
}
10671070
return result->message->record_v->fields;
10681071
}
10691072

10701073
const mg_map *mg_result_summary(const mg_result *result) {
1074+
if (!result->message) {
1075+
return NULL;
1076+
}
10711077
if (result->message->type != MG_MESSAGE_TYPE_SUCCESS) {
10721078
return NULL;
10731079
}

src/mgconstants.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,7 @@
2727
#define MG_TINY_SIZE_MAX 15
2828

2929
static const char MG_HANDSHAKE_MAGIC[] = "\x60\x60\xB0\x17";
30-
31-
// TODO(gitbuda): Align this with the mgclient library version.
32-
static const char MG_USER_AGENT_DEFAULT[] = "MemgraphBolt/0.1";
30+
static const char MG_USER_AGENT[] = "mgclient/" MGCLIENT_VERSION;
3331

3432
/// Markers
3533
#define MG_MARKER_NULL 0xC0

tests/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,7 @@ add_test(example_basic_c example_basic_c 127.0.0.1 7687 "RETURN 1")
106106
add_executable(example_basic_cpp ${EXAMPLE_DIR}/basic.cpp)
107107
target_link_libraries(example_basic_cpp mgclient-static project_cpp_warnings)
108108
add_test(example_basic_cpp example_basic_cpp 127.0.0.1 7687 "RETURN 1")
109+
110+
add_executable(example_advanced_cpp ${EXAMPLE_DIR}/advanced.cpp)
111+
target_link_libraries(example_advanced_cpp mgclient-static project_cpp_warnings)
112+
add_test(example_advanced_cpp example_advanced_cpp 127.0.0.1 7687)

0 commit comments

Comments
 (0)