├── .DS_Store
├── LICENSE
├── README.md
├── api.cpp
├── api.hpp
├── base64.hpp
├── database.cpp
├── database.hpp
├── kit.cpp
└── kit.hpp
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skybluezx/Neo4j-cpp-driver/9cdb21df23631dc5f31644070bae499fd5b59f78/.DS_Store
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Xiao Zhai
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Neo4j-cpp-driver
2 | C++的Neo4j驱动,该驱动基于libcurl和Neo4j的REST接口实现了C++对Neo4j的操作,具体的接口方法参照了Neo4j官方为Node.js提供的功能。
3 |
4 | ## 依赖
5 | 该驱动依赖libcurl和JsonCpp,在使用该驱动前请先安装配置好上述依赖库。
6 | libcurl头文件在api.hpp中被引入,JsonCpp头文件在api.hpp和kit.hpp中被引入,在安装配置完依赖库后,需对应调整此处的头文件并引入库文件。
7 |
8 | ## 组成简介
9 | 该驱动包括database、api、kit和base64四个部分组成。
10 |
11 | ### database.hpp/cpp
12 | 该模块为驱动的底层模块,主要用于curl的初始化和析构时的清理操作。
13 |
`由于curl的特性,初始化部分使用了单例模式`
14 |
15 | ### api.hpp/cpp
16 | 该模块为驱动的核心部分,主要包括增删改查等各类数据库操作。
17 |
18 | ### kit.hpp/cpp
19 | 该模块中包括若干方法,主要用于解析HTTP协议头中的状态码、生成条件字符串等功能。
20 |
21 | ### base64.hpp
22 | Neo4j在登录验证时使用了Base64编码,该组件用于对数据库连接验证时的密码进行编码处理。
23 |
24 | ## 示例
25 | try
26 | {
27 | //使用单例模式获得Neo4j驱动
28 | std::shared_ptr neo4j = neo4jDriver::Neo4j::getNeo4j();
29 | //利用Neo4j驱动和连接参数生成API对象
30 | neo4jDriver::Neo4jAPI neo4jAPI(neo4j, "127.0.0.1", "7474", "neo4j", "123456");
31 | //连接数据库
32 | neo4jAPI.connectDatabase();
33 |
34 | //具体的数据库操作
35 | //......
36 |
37 | //断开数据库连接
38 | neo4jAPI.closeDatabase();
39 | //清理数据库驱动
40 | neo4j->deleteNeo4j();
41 | }
42 | catch (char* e)
43 | {
44 | std::cout << e << std::endl;
45 | }
46 |
47 | ## API
48 | `尚未提供,请参照api.hpp`
49 |
50 | ## 许可协议
51 | Neo4j-cpp-driver使用MIT许可证。关于Neo4j-cpp-driver依赖项的协议见对应依赖项的License文件。
52 |
--------------------------------------------------------------------------------
/api.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // api.cpp
3 | // Neo4j-cpp-driver
4 | //
5 | // Created by skyblue on 2017/7/9.
6 | // Copyright © 2017年 skyblue. All rights reserved.
7 | //
8 |
9 | #include "api.hpp"
10 |
11 | #include
12 |
13 | #include "./base64.hpp"
14 |
15 | #include "./kit.hpp"
16 |
17 | namespace neo4jDriver
18 | {
19 | Neo4jAPI::Neo4jAPI(std::shared_ptr database)
20 | :database(database), headers(NULL), curl(NULL), responseHeaderString(""), responseString("")
21 | {
22 |
23 | };
24 |
25 | Neo4jAPI::Neo4jAPI(std::shared_ptr database, std::string host, std::string port, std::string user, std::string password)
26 | :database(database), host(host), port(port), user(user), password(password), headers(NULL), curl(NULL), responseHeaderString(""), responseString("")
27 | {
28 |
29 | };
30 |
31 | std::string Neo4jAPI::getHost()
32 | {
33 | return this->host;
34 | };
35 |
36 | std::string Neo4jAPI::getPort()
37 | {
38 | return this->port;
39 | };
40 |
41 | std::string Neo4jAPI::getUser()
42 | {
43 | return this->user;
44 | };
45 |
46 | std::string Neo4jAPI::getPassword()
47 | {
48 | return this->password;
49 | };
50 |
51 | void Neo4jAPI::connectDatabase()
52 | {
53 | this->headers = curl_slist_append(this->headers, "Accept: application/json; charset=UTF-8");
54 | this->headers = curl_slist_append(this->headers, "Content-Type: application/json");
55 | this->headers = curl_slist_append(this->headers, "X-Stream: true");
56 |
57 | std::string userAndPasswordString = this->getUser() + ":" + this->getPassword(), userAndPasswordEncodeString;
58 | Base64::Encode(userAndPasswordString, &userAndPasswordEncodeString);
59 | userAndPasswordEncodeString = "Authorization: Basic " + userAndPasswordEncodeString;
60 | this->headers = curl_slist_append(this->headers, userAndPasswordEncodeString.c_str());
61 |
62 | this->curl = curl_easy_init();
63 |
64 | if (this->curl)
65 | {
66 | //指定header
67 | curl_easy_setopt(this->curl, CURLOPT_HTTPHEADER, this->headers);
68 | //指定接收返回协议头的回调方法
69 | curl_easy_setopt(this->curl, CURLOPT_HEADERFUNCTION, Neo4jAPI::responseHeaderHandeler);
70 | //指定接收返回协议头的存储位置
71 | curl_easy_setopt(this->curl, CURLOPT_HEADERDATA, &this->responseHeaderString);
72 | //指定接收数据的回调方法
73 | curl_easy_setopt(this->curl, CURLOPT_WRITEFUNCTION, Neo4jAPI::responseHandeler);
74 | //指定接收数据的存储位置
75 | curl_easy_setopt(this->curl, CURLOPT_WRITEDATA, &this->responseString);
76 |
77 | //发送请求,测试数据库是否已连接成功
78 | std::string httpUrlForTransaction = "http://" + host + ":" + port + "/user/neo4j";
79 | //指定访问点
80 | curl_easy_setopt(this->curl, CURLOPT_URL, httpUrlForTransaction.c_str());
81 | //执行POST请求
82 | CURLcode res = curl_easy_perform(curl);
83 | //根据执行结果返回执行结果或抛出异常
84 | if (res != 0)
85 | {
86 | //post请求执行失败,抛出异常
87 | throw "POST REQUEST EXECUTION IS FAILED!";
88 | }
89 |
90 | //对返回数据的协议状态进行检查
91 | std::string statusCode = Kit::getStatusCode(this->responseHeaderString);
92 |
93 | if (statusCode != "200")
94 | {
95 | this->responseHeaderString = "";
96 | this->responseString = "";
97 |
98 | throw "RESPONSE STATUS IS NOT 200!";
99 | }
100 |
101 | this->responseHeaderString = "";
102 | this->responseString = "";
103 | }
104 | else
105 | {
106 | //curl_easy初始化失败,抛出异常
107 | throw "CURL EASY INIT IS FAILED!";
108 | }
109 | };
110 |
111 | void Neo4jAPI::closeDatabase()
112 | {
113 | this->responseHeaderString = "";
114 | this->responseString = "";
115 |
116 | if (this->headers != NULL)
117 | {
118 | curl_slist_free_all(this->headers);
119 | this->headers = NULL;
120 | }
121 |
122 | if (this->curl)
123 | {
124 | curl_easy_cleanup(this->curl);
125 | this->curl = NULL;
126 | }
127 | };
128 |
129 | Json::Value Neo4jAPI::cypherQuery(std::string cypher, Json::Value properties)
130 | {
131 | if (this->curl)
132 | {
133 | std::string httpUrlForTransaction = "http://" + host + ":" + port + "/db/data/transaction/commit";
134 |
135 | //指定访问点
136 | curl_easy_setopt(this->curl, CURLOPT_URL, httpUrlForTransaction.c_str());
137 |
138 | //通过Json构建Cypher语句的查询字符串
139 | Json::Value statement;
140 | Json::Value statements;
141 | Json::Value cypherJson;
142 | Json::FastWriter writer;
143 |
144 | //构建单条statement
145 | statement["statement"] = cypher;
146 |
147 | if (properties != Json::nullValue)
148 | {
149 | statement["parameters"] = properties;
150 | }
151 |
152 | //构建statement数组
153 | statements.append(statement);
154 | //构建查询对象
155 | cypherJson["statements"] = statements;
156 |
157 | //将Json格式的查询对象输出为字符串
158 | std::string cypherString = writer.write(cypherJson);
159 |
160 | //指定请求方式为POST
161 | curl_easy_setopt(this->curl, CURLOPT_POST, 1);
162 | //将Cypher语句填充至POST的数据段中
163 | curl_easy_setopt(this->curl, CURLOPT_POSTFIELDS, cypherString.c_str());
164 | curl_easy_setopt(this->curl, CURLOPT_CUSTOMREQUEST, "POST");
165 |
166 | //执行POST请求
167 | CURLcode res = curl_easy_perform(curl);
168 |
169 | //根据执行结果返回执行结果或抛出异常
170 | if (res != 0)
171 | {
172 | //post请求执行失败,抛出异常
173 | throw "POST REQUEST EXECUTION IS FAILED!";
174 | }
175 | else
176 | {
177 | //对返回数据的协议状态进行检查
178 | std::string statusCode = Kit::getStatusCode(this->responseHeaderString);
179 |
180 | if (statusCode != "200")
181 | {
182 | this->responseHeaderString = "";
183 | this->responseString = "";
184 |
185 | throw "RESPONSE STATUS IS NOT 200!";
186 | }
187 |
188 | //成功返回执行结果,对结果进行分析处理
189 |
190 | Json::Value responseJson;
191 | Json::Value results;
192 | Json::Value errors;
193 | Json::Reader reader;
194 |
195 | //将返回字符串解析为Json对象
196 | if (reader.parse(this->responseString, responseJson))
197 | {
198 | this->responseHeaderString = "";
199 | this->responseString = "";
200 |
201 | //取出其中的错误部分
202 | errors = responseJson["errors"];
203 |
204 | //判断语句执行是否发生错误
205 | if (errors.size() != 0)
206 | {
207 | //若错误部分不为空,抛出异常
208 | throw "CYPHER IS ERROR!";
209 | }
210 | else
211 | {
212 | //未发生错误,提取查询结果
213 | results = responseJson["results"];
214 |
215 | //判断查询结果是否为空
216 | if (results.size() == 1)
217 | {
218 | //不为空,返回结果(本方法只支持单Cypher语句的执行,所以若有结果只有一条)
219 | return results[0];
220 | }
221 | else
222 | {
223 | //为空或多于一条,格式错误,抛出异常
224 | throw "RESULT IS ERROR!";
225 | }
226 | }
227 | }
228 | else
229 | {
230 | this->responseHeaderString = "";
231 | this->responseString = "";
232 |
233 | //解析失败,抛出异常
234 | throw "RESPONSE FORMAT IS ERROR!";
235 | }
236 | }
237 | }
238 | else
239 | {
240 | throw "CURL EASY INIT IS FAILED!";
241 | }
242 | };
243 |
244 | Json::Value Neo4jAPI::createNode(const Json::Value &properties, const std::string &label)
245 | {
246 | if (this->curl)
247 | {
248 | std::string httpUrlForTransaction = "http://" + this->host + ":" + this->port + "/db/data/transaction/commit";
249 |
250 | //指定访问点
251 | curl_easy_setopt(this->curl, CURLOPT_URL, httpUrlForTransaction.c_str());
252 |
253 | //通过Json构建Cypher语句的查询字符串
254 | Json::Value statement;
255 | Json::Value parameters;
256 | Json::Value statements;
257 | Json::Value cypherJson;
258 | Json::FastWriter writer;
259 | std::string cypher, cypherString;
260 |
261 | if (label != "")
262 | {
263 | if (!properties.empty())
264 | {
265 | cypher = "CREATE (data:" + label + " {propertyes}) RETURN data";
266 | }
267 | else
268 | {
269 | cypher = "CREATE (data:" + label + ") RETURN data";
270 | }
271 | }
272 | else
273 | {
274 | if (!properties.empty())
275 | {
276 | cypher = "CREATE (data {propertyes}) RETURN data";
277 | }
278 | else
279 | {
280 | cypher = "CREATE (data) RETURN data";
281 | }
282 | }
283 |
284 | statement["statement"] = cypher;
285 |
286 | parameters["propertyes"] = properties;
287 | statement["parameters"] = parameters;
288 |
289 | statement["resultDataContents"].append("REST");
290 |
291 | statements.append(statement);
292 |
293 | cypherJson["statements"] = statements;
294 | cypherString = writer.write(cypherJson);
295 |
296 | //指定请求方式为POST
297 | curl_easy_setopt(this->curl, CURLOPT_POST, 1);
298 | //将Cypher语句填充至POST的数据段中
299 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, cypherString.c_str());
300 |
301 | //执行POST请求
302 | CURLcode res = curl_easy_perform(this->curl);
303 |
304 | //根据执行结果返回执行结果或抛出异常
305 | if (res != 0)
306 | {
307 | //post请求执行失败,抛出异常
308 | throw "POST REQUEST ERROR!";
309 | }
310 | else
311 | {
312 | //对返回数据的协议状态进行检查
313 | std::string statusCode = Kit::getStatusCode(this->responseHeaderString);
314 |
315 | if (statusCode != "200")
316 | {
317 | this->responseHeaderString = "";
318 | this->responseString = "";
319 |
320 | throw "RESPONSE STATUS IS NOT 200!";
321 | }
322 |
323 | //成功返回执行结果,对结果进行分析处理
324 |
325 | Json::Value responseJson;
326 | Json::Value results;
327 | Json::Value errors;
328 | Json::Reader reader;
329 |
330 | //将返回字符串解析为Json对象
331 | if (reader.parse(this->responseString, responseJson))
332 | {
333 | this->responseHeaderString = "";
334 | this->responseString = "";
335 |
336 | //取出其中的错误部分
337 | errors = responseJson["errors"];
338 |
339 | //判断语句执行是否发生错误
340 | if (errors.size() != 0)
341 | {
342 | //若错误部分不为空,抛出异常
343 | throw "CYPHER IS ERROR!";
344 | }
345 | else
346 | {
347 | //未发生错误,提取查询结果
348 | results = responseJson["results"];
349 |
350 | //判断查询结果是否为空
351 | if (results.size() == 1)
352 | {
353 | //不为空,返回结果
354 | Json::Value result = results[0];
355 | Json::Value data = result["data"];
356 | Json::Value rests = data[0]["rest"];
357 | Json::Value rest = rests[0];
358 | Json::Value node = rest["data"];
359 | Json::Value metadata = rest["metadata"];
360 |
361 | node["_id"] = metadata["id"];
362 | node["_labels"] = metadata["labels"];
363 |
364 | return node;
365 | }
366 | else
367 | {
368 | //为空或多于一条,格式错误,抛出异常
369 | throw "RESULT IS ERROR!";
370 | }
371 | }
372 | }
373 | else
374 | {
375 | this->responseHeaderString = "";
376 | this->responseString = "";
377 |
378 | //解析失败,抛出异常
379 | throw "RESPONSE PARSE IS ERROR!";
380 | }
381 | }
382 | }
383 | else
384 | {
385 | throw "CURL EASY INIT IS FAILED!";
386 | }
387 | };
388 |
389 | Json::Value Neo4jAPI::createNode(const Json::Value &properties, const std::vector &labels)
390 | {
391 | return this->createNode(properties, Kit::getLabelString(labels));
392 | };
393 |
394 | bool Neo4jAPI::deleteNode(unsigned long long int nodeID)
395 | {
396 | if (this->curl)
397 | {
398 | std::stringstream sstream;
399 | sstream << nodeID;
400 | std::string nodeIDString;
401 | sstream >> nodeIDString;
402 | sstream.clear();
403 |
404 | std::string httpUrl = "http://" + this->host + ":" + this->port + "/db/data/node/" + nodeIDString;
405 |
406 | //指定访问点
407 | curl_easy_setopt(this->curl, CURLOPT_URL, httpUrl.c_str());
408 | //指定请求方式为DELETE
409 | curl_easy_setopt(this->curl, CURLOPT_CUSTOMREQUEST, "DELETE");
410 |
411 | //执行DELETE请求
412 | CURLcode res = curl_easy_perform(curl);
413 |
414 | //根据执行结果返回执行结果或抛出异常
415 | if (res != 0)
416 | {
417 | //post请求执行失败,抛出异常
418 | throw "DELETE REQUEST EXECUTION IS FAILED!";
419 | }
420 | else
421 | {
422 | //对返回数据的协议状态进行检查
423 | std::string statusCode = Kit::getStatusCode(this->responseHeaderString);
424 |
425 | this->responseHeaderString = "";
426 | this->responseString = "";
427 |
428 | /*
429 | * 删除成功后的状态码和文档描述不一致
430 | * 文档中为204,但实际返回200
431 | */
432 |
433 | if (statusCode == "204" || statusCode == "200")
434 | {
435 | //删除成功
436 | return true;
437 | }
438 | else if (statusCode == "404")
439 | {
440 | //未找到该点
441 | return false;
442 | }
443 | else if (statusCode == "409")
444 | {
445 | //该点存在依附于它的边,无法删除
446 | return false;
447 | }
448 | else
449 | {
450 | //解析失败,抛出异常
451 | throw "RESPONSE STATUS IS ERROR!";
452 | }
453 | }
454 | }
455 | else
456 | {
457 | throw "CURL EASY INIT IS FAILED!";
458 | }
459 | };
460 |
461 | bool Neo4jAPI::deleteNodeAndAllRelationshipsOfTheNode(unsigned long long int nodeID)
462 | {
463 | /*
464 | * 这个版本有问题,可能出现删除了全部边后因为网络问题没有将点删除的问题,健壮性依赖于网络
465 | * 改进方案,使用事务处理
466 | */
467 |
468 | this->deleteAllRelationshipsOfOneNode(nodeID);
469 |
470 | return this->deleteNode(nodeID);
471 | };
472 |
473 | unsigned long long int Neo4jAPI::deleteNodeByLabelAndProperties(std::string label, Json::Value &properties)
474 | {
475 | std::string cypher = "";
476 | std::string whereString = Kit::getWhereString("data", properties);
477 |
478 | if (label != "")
479 | {
480 | cypher = "MATCH (data:" + label + ")";
481 | }
482 | else
483 | {
484 | cypher = "MATCH (data)";
485 | }
486 |
487 | if (whereString != "")
488 | {
489 | cypher += " WHERE " + whereString;
490 | }
491 |
492 | cypher += " DELETE data RETURN count(data)";
493 |
494 | //解析过程是否发生异常严重依赖返回的数据,该怎么看待和处理?
495 | Json::Value result = this->cypherQuery(cypher, properties);
496 | Json::Value data = result["data"];
497 | Json::Value rows = data[0];
498 | Json::Value row = rows["row"];
499 | Json::Value count = row[0];
500 |
501 | return count.asLargestUInt();
502 | };
503 |
504 | unsigned long long int Neo4jAPI::deleteNodeByLabelsAndProperties(std::vector &labels, Json::Value &properties)
505 | {
506 | return this->deleteNodeByLabelAndProperties(Kit::getLabelString(labels), properties);
507 | };
508 |
509 | bool Neo4jAPI::getNode(unsigned long long int nodeID, Json::Value &node)
510 | {
511 | if (this->curl)
512 | {
513 | std::stringstream sstream;
514 | sstream << nodeID;
515 | std::string nodeIDString;
516 | sstream >> nodeIDString;
517 | sstream.clear();
518 |
519 | std::string httpUrl = "http://" + this->host + ":" + this->port + "/db/data/node/" + nodeIDString;
520 |
521 | //指定访问点
522 | curl_easy_setopt(this->curl, CURLOPT_URL, httpUrl.c_str());
523 | //指定请求方式为GET
524 | curl_easy_setopt(this->curl, CURLOPT_CUSTOMREQUEST, "GET");
525 |
526 | //执行GET请求
527 | CURLcode res = curl_easy_perform(this->curl);
528 |
529 | //根据执行结果返回执行结果或抛出异常
530 | if (res != 0)
531 | {
532 | //post请求执行失败,抛出异常
533 | throw "GET REQUEST EXECUTION IS FAILED!";
534 | }
535 | else
536 | {
537 | //对返回数据的协议状态进行检查
538 | std::string statusCode = Kit::getStatusCode(this->responseHeaderString);
539 |
540 | if (statusCode == "200")
541 | {
542 | //成功找到该点
543 | Json::Reader reader;
544 | Json::Value responseJson;
545 | Json::Value metaData;
546 |
547 | reader.parse(this->responseString, responseJson);
548 |
549 | this->responseHeaderString = "";
550 | this->responseString = "";
551 |
552 | metaData = responseJson["metadata"];
553 |
554 | node = responseJson["data"];
555 | node["_id"] = metaData["id"];
556 | node["_labels"] = metaData["labels"];
557 |
558 | return true;
559 | }
560 | else if (statusCode == "404")
561 | {
562 | this->responseHeaderString = "";
563 | this->responseString = "";
564 |
565 | //未找到该点
566 | return false;
567 | }
568 | else
569 | {
570 | this->responseHeaderString = "";
571 | this->responseString = "";
572 |
573 | //解析失败,抛出异常
574 | throw "RESPONSE STATUS IS ERROR!";
575 | }
576 | }
577 | }
578 | else
579 | {
580 | throw "CURL EASY INIT IS FAILED!";
581 | }
582 | };
583 |
584 | Json::Value Neo4jAPI::selectNodesByLabelAndProperties(std::string label, Json::Value &properties)
585 | {
586 | if (this->curl)
587 | {
588 | std::string httpUrlForTransaction = "http://" + this->host + ":" + this->port + "/db/data/transaction/commit";
589 |
590 | //指定访问点
591 | curl_easy_setopt(this->curl, CURLOPT_URL, httpUrlForTransaction.c_str());
592 |
593 | //通过Json构建Cypher语句的查询字符串
594 | Json::Value statement;
595 | Json::Value statements;
596 | Json::Value root;
597 | Json::FastWriter writer;
598 | std::string cypher = "", whereString = Kit::getWhereString("data", properties), rootString;
599 |
600 | if (label != "")
601 | {
602 | cypher = "MATCH (data:" + label + ")";
603 | }
604 | else
605 | {
606 | cypher = "MATCH (data)";
607 | }
608 |
609 | if (whereString != "")
610 | {
611 | cypher += " WHERE " + whereString;
612 | }
613 |
614 | cypher += " RETURN data";
615 |
616 | statement["statement"] = cypher;
617 | statement["parameters"] = properties;
618 | statement["resultDataContents"].append("REST");
619 |
620 | statements.append(statement);
621 |
622 | root["statements"] = statements;
623 | rootString = writer.write(root);
624 |
625 | //指定请求方式为POST
626 | curl_easy_setopt(this->curl, CURLOPT_POST, 1);
627 | //将Cypher语句填充至POST的数据段中
628 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, rootString.c_str());
629 | curl_easy_setopt(this->curl, CURLOPT_CUSTOMREQUEST, "POST");
630 |
631 | //执行POST请求
632 | CURLcode res = curl_easy_perform(curl);
633 |
634 | //根据执行结果返回执行结果或抛出异常
635 | if (res != 0)
636 | {
637 | //post请求执行失败,抛出异常
638 | throw "POST REQUEST EXECUTION IS FAILED!";
639 | }
640 | else
641 | {
642 | //对返回数据的协议状态进行检查
643 | std::string statusCode = Kit::getStatusCode(this->responseHeaderString);
644 |
645 | if (statusCode != "200")
646 | {
647 | this->responseHeaderString = "";
648 | this->responseString = "";
649 |
650 | throw "RESPONSE STATUS IS ERROR!";
651 | }
652 |
653 | //成功返回执行结果,对结果进行分析处理
654 |
655 | Json::Value responseJson;
656 | Json::Value results;
657 | Json::Value errors;
658 | Json::Reader reader;
659 |
660 | //将返回字符串解析为Json对象
661 | if (reader.parse(this->responseString, responseJson))
662 | {
663 | this->responseHeaderString = "";
664 | this->responseString = "";
665 |
666 | //取出其中的错误部分
667 | errors = responseJson["errors"];
668 |
669 | //判断语句执行是否发生错误
670 | if (errors.size() != 0)
671 | {
672 | //若错误部分不为空,抛出异常
673 | throw "CYPHER IS ERROR!";
674 | }
675 | else
676 | {
677 | //未发生错误,提取查询结果
678 | results = responseJson["results"];
679 |
680 | //判断查询结果是否为空
681 | if (results.size() == 1)
682 | {
683 | //不为空,返回结果
684 | Json::Value result = results[0];
685 | Json::Value data = result["data"];
686 | Json::Value rests;
687 | Json::Value rest;
688 | Json::Value node;
689 | Json::Value metadata;
690 | Json::Value nodeList;
691 |
692 | for (int i = 0; i < data.size(); i++)
693 | {
694 | rests = data[i]["rest"];
695 | rest = rests[0];
696 | node = rest["data"];
697 | metadata = rest["metadata"];
698 | node["_id"] = metadata["id"];
699 | node["_labels"] = metadata["labels"];
700 |
701 | nodeList.append(node);
702 | }
703 |
704 | return nodeList;
705 | }
706 | else
707 | {
708 | //为空或多于一条,格式错误,抛出异常
709 | throw "RESULT IS ERROR!";
710 | }
711 | }
712 | }
713 | else
714 | {
715 | this->responseHeaderString = "";
716 | this->responseString = "";
717 |
718 | //解析失败,抛出异常
719 | throw "RESPONSE PARSE IS ERROR!";
720 | }
721 | }
722 | }
723 | else
724 | {
725 | throw "CURL EASY INIT IS FAILED!";
726 | }
727 | };
728 |
729 | Json::Value Neo4jAPI::selectNodesByLabelsAndProperties(std::vector &labels, Json::Value &properties)
730 | {
731 | return this->selectNodesByLabelAndProperties(Kit::getLabelString(labels), properties);
732 | };
733 |
734 | Json::Value Neo4jAPI::selectNodesByAnotherLinkedNode(std::string selectedLabel, Json::Value &selectedProperties, std::string relationType, Json::Value &relationProperties, std::string linkedLabel, Json::Value &linkedProperties)
735 | {
736 | //初始化cypher语句为空
737 | std::string cypher = "";
738 |
739 | //初始化查询实体、关联关系和关联实体的where子句为空
740 | std::string selectedWhereString = "";
741 | std::string relationWhereString = "";
742 | std::string linkedWhereString = "";
743 |
744 | //初始化查询参数
745 | Json::Value properties;
746 | //声明参数枚举器
747 | Json::ValueIterator property;
748 |
749 | //处理查询实体的参数并添加进最终的查询参数对象中
750 | if (selectedProperties != Json::nullValue)
751 | {
752 | for (property = selectedProperties.begin(); property != selectedProperties.end(); property++)
753 | {
754 | properties["n_" + property.name()] = selectedProperties[property.name()];
755 | }
756 |
757 | selectedWhereString = Kit::getWhereString("n", "n_", selectedProperties, "_id");
758 | }
759 |
760 | if (relationProperties != Json::nullValue)
761 | {
762 | for (property = relationProperties.begin(); property != relationProperties.end(); property++)
763 | {
764 | properties["r_" + property.name()] = relationProperties[property.name()];
765 | }
766 |
767 | relationWhereString = Kit::getWhereString("r", "r_", relationProperties, "_id");
768 | }
769 |
770 | if (linkedProperties != Json::nullValue)
771 | {
772 | for (property = linkedProperties.begin(); property != linkedProperties.end(); property++)
773 | {
774 | properties["m_" + property.name()] = linkedProperties[property.name()];
775 | }
776 |
777 | linkedWhereString = Kit::getWhereString("m", "m_", linkedProperties, "_id");
778 | }
779 |
780 | //拼接cypher语句
781 |
782 | if (linkedLabel != "")
783 | {
784 | cypher = "MATCH (m:" + linkedLabel + ")";
785 | }
786 | else
787 | {
788 | cypher = "MATCH (m)";
789 | }
790 |
791 | if (relationType != "")
792 | {
793 | cypher += "-[r:" + relationType +"]-";
794 | }
795 | else
796 | {
797 | cypher += "-[r]-";
798 | }
799 |
800 | if (selectedLabel != "")
801 | {
802 | cypher += "(n:" + selectedLabel +")";
803 | }
804 | else
805 | {
806 | cypher += "(n)";
807 | }
808 |
809 | /*
810 | *拼接where字句
811 | */
812 |
813 | if (selectedWhereString != "")
814 | {
815 | //selectedWhereString不为空时
816 | cypher += " WHERE " + selectedWhereString;
817 | }
818 |
819 | if (selectedWhereString != "" && relationWhereString != "")
820 | {
821 | //selectedWhereString和relationWhereString全部不为空
822 | cypher += " AND " + relationWhereString;
823 | }
824 | else if (relationWhereString != "")
825 | {
826 | //selectedWhereString为空且relationWhereString不为空
827 | cypher += " WHERE " + relationWhereString;
828 | }
829 |
830 | if ((selectedWhereString != "" || relationWhereString != "") && linkedWhereString != "")
831 | {
832 | //selectedWhereString和relationWhereString至少一个不为空且linkedWhereString不为空
833 | cypher += " AND " + linkedWhereString;
834 | }
835 | else if (linkedWhereString != "")
836 | {
837 | //selectedWhereString和relationWhereString全为空且linkedWhereString不为空
838 | cypher += " WHERE " + linkedWhereString;
839 | }
840 |
841 | cypher += " RETURN id(n),n";
842 |
843 | //解析过程是否发生异常严重依赖返回的数据,该怎么看待和处理?
844 | Json::Value result = this->cypherQuery(cypher, properties);
845 | Json::Value data = result["data"];
846 |
847 | Json::Value nodeList;
848 |
849 | for (int i = 0; i < data.size(); i++)
850 | {
851 | Json::Value row = data[i]["row"];
852 |
853 | Json::Value node = row[1];
854 | node["_id"] = row[0].asLargestUInt();
855 |
856 | nodeList.append(node);
857 | }
858 |
859 | return nodeList;
860 | };
861 |
862 | Json::Value Neo4jAPI::selectNodesByAnotherLinkedNode(std::string selectedLabel, Json::Value &selectedProperties, std::string relationType, Json::Value &relationProperties, unsigned long long int linkNodeID)
863 | {
864 | std::string linkNodeIDString;
865 |
866 | std::stringstream sstream;
867 | sstream << linkNodeID;
868 | sstream >> linkNodeIDString;
869 | sstream.clear();
870 |
871 | //初始化cypher语句为空
872 | std::string cypher = "";
873 |
874 | //初始化查询实体和关联关系的where子句为空
875 | std::string selectedWhereString = "";
876 | std::string relationWhereString = "";
877 |
878 | //初始化查询参数
879 | Json::Value properties;
880 | //声明参数枚举器
881 | Json::ValueIterator property;
882 |
883 | //处理查询实体的参数并添加进最终的查询参数对象中
884 | if (selectedProperties != Json::nullValue)
885 | {
886 | for (property = selectedProperties.begin(); property != selectedProperties.end(); property++)
887 | {
888 | properties["n_" + property.name()] = selectedProperties[property.name()];
889 | }
890 |
891 | selectedWhereString = Kit::getWhereString("n", "n_", selectedProperties, "_id");
892 | }
893 |
894 | if (relationProperties != Json::nullValue)
895 | {
896 | for (property = relationProperties.begin(); property != relationProperties.end(); property++)
897 | {
898 | properties["r_" + property.name()] = relationProperties[property.name()];
899 | }
900 |
901 | relationWhereString = Kit::getWhereString("r", "r_", relationProperties, "_id");
902 | }
903 |
904 | //拼接cypher语句
905 |
906 | cypher = "MATCH (m)";
907 |
908 | if (relationType != "")
909 | {
910 | cypher += "-[r:" + relationType +"]-";
911 | }
912 | else
913 | {
914 | cypher += "-[r]-";
915 | }
916 |
917 | if (selectedLabel != "")
918 | {
919 | cypher += "(n:" + selectedLabel +")";
920 | }
921 | else
922 | {
923 | cypher += "(n)";
924 | }
925 |
926 | /*
927 | *拼接where字句
928 | */
929 |
930 | if (selectedWhereString != "")
931 | {
932 | //selectedWhereString不为空时
933 | cypher += " WHERE " + selectedWhereString;
934 | }
935 |
936 | if (selectedWhereString != "" && relationWhereString != "")
937 | {
938 | //selectedWhereString和relationWhereString全部不为空
939 | cypher += " AND " + relationWhereString;
940 | }
941 | else if (relationWhereString != "")
942 | {
943 | //selectedWhereString为空且relationWhereString不为空
944 | cypher += " WHERE " + relationWhereString;
945 | }
946 |
947 | if (selectedWhereString != "" || relationWhereString != "")
948 | {
949 | //selectedWhereString和relationWhereString至少一个不为空
950 | cypher += " AND id(m)=" + linkNodeIDString;
951 | }
952 | else
953 | {
954 | //selectedWhereString和relationWhereString全为空
955 | cypher += " WHERE id(m)=" + linkNodeIDString;
956 | }
957 |
958 | cypher += " RETURN id(n),n";
959 |
960 | //解析过程是否发生异常严重依赖返回的数据,该怎么看待和处理?
961 | Json::Value result = this->cypherQuery(cypher, properties);
962 | Json::Value data = result["data"];
963 |
964 | Json::Value nodeList;
965 |
966 | for (int i = 0; i < data.size(); i++)
967 | {
968 | Json::Value row = data[i]["row"];
969 |
970 | Json::Value node = row[1];
971 | node["_id"] = row[0].asLargestUInt();
972 |
973 | nodeList.append(node);
974 | }
975 |
976 | return nodeList;
977 | };
978 |
979 | bool Neo4jAPI::updateNodeByID(unsigned long long int nodeID, Json::Value &properties)
980 | {
981 | std::string cypher = "START data=node({_id}) SET " + Kit::getSetString("data", properties) + " RETURN data";
982 |
983 | properties["_id"] = nodeID;
984 |
985 | //解析过程是否发生异常严重依赖返回的数据,该怎么看待和处理?
986 | Json::Value result = this->cypherQuery(cypher, properties);
987 | Json::Value data = result["data"];
988 | Json::Value rows = data[0];
989 | Json::Value count = rows.size();
990 |
991 | if (count.asLargestUInt() == 1)
992 | {
993 | return true;
994 | }
995 | else
996 | {
997 | return false;
998 | }
999 | };
1000 |
1001 | bool Neo4jAPI::replaceNodeByID(unsigned long long int nodeID, Json::Value &properties)
1002 | {
1003 | if (this->curl)
1004 | {
1005 | std::stringstream sstream;
1006 | sstream << nodeID;
1007 | std::string nodeIDString;
1008 | sstream >> nodeIDString;
1009 | sstream.clear();
1010 |
1011 | std::string httpUrl = "http://" + this->host + ":" + this->port + "/db/data/node/" + nodeIDString + "/properties";
1012 |
1013 | //指定访问点
1014 | curl_easy_setopt(this->curl, CURLOPT_URL, httpUrl.c_str());
1015 |
1016 | Json::FastWriter writer;
1017 |
1018 | std::string propertiesString = writer.write(properties);
1019 |
1020 | //指定请求方式为PUT
1021 | curl_easy_setopt(this->curl, CURLOPT_CUSTOMREQUEST, "PUT");
1022 |
1023 | /*
1024 | * 指定请求方式为PUT,但却将数据放进了POSTFIELDS,这样是稳定的吗?
1025 | */
1026 |
1027 | //将Cypher语句填充至POST的数据段中
1028 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, propertiesString.c_str());
1029 |
1030 | //执行PUT请求
1031 | CURLcode res = curl_easy_perform(curl);
1032 |
1033 | //根据执行结果返回执行结果或抛出异常
1034 | if (res != 0)
1035 | {
1036 | //post请求执行失败,抛出异常
1037 | throw "POST REQUEST EXECUTION IS FAILED!";
1038 | }
1039 | else
1040 | {
1041 | //对返回数据的协议状态进行检查
1042 | std::string statusCode = Kit::getStatusCode(this->responseHeaderString);
1043 |
1044 | this->responseHeaderString = "";
1045 | this->responseString = "";
1046 |
1047 | if (statusCode == "204")
1048 | {
1049 | return true;
1050 | }
1051 | else if (statusCode == "404")
1052 | {
1053 | return false;
1054 | }
1055 | else
1056 | {
1057 | //解析失败,抛出异常
1058 | throw "RESPONSE STATUS IS ERROR!";
1059 | }
1060 | }
1061 | }
1062 | else
1063 | {
1064 | throw "CURL EASY INIT IS FAILED!";
1065 | }
1066 | };
1067 |
1068 | bool Neo4jAPI::insertRelationship(unsigned long long int rootNodeID, unsigned long long int otherNodeID, std::string typeName, Json::Value &properties, Json::Value &relationship)
1069 | {
1070 | if (this->curl)
1071 | {
1072 | std::stringstream sstream;
1073 | sstream << rootNodeID;
1074 | std::string rootNodeIDString;
1075 | sstream >> rootNodeIDString;
1076 | sstream.clear();
1077 |
1078 | std::string httpUrl = "http://" + this->host + ":" + this->port + "/db/data/node/" + rootNodeIDString + "/relationships";
1079 |
1080 | //指定访问点
1081 | curl_easy_setopt(this->curl, CURLOPT_URL, httpUrl.c_str());
1082 |
1083 | Json::Value root;
1084 | Json::FastWriter writer;
1085 |
1086 | sstream << otherNodeID;
1087 | std::string otherNodeIDString;
1088 | sstream >> otherNodeIDString;
1089 | sstream.clear();
1090 |
1091 | root["to"] = "http://" + this->host + ":" + this->port + "/db/data/node/" + otherNodeIDString;
1092 | root["type"] = typeName;
1093 | root["data"] = properties;
1094 |
1095 | std::string rootString = writer.write(root);
1096 |
1097 | //指定请求方式为POST
1098 | curl_easy_setopt(this->curl, CURLOPT_POST, 1);
1099 | //将Cypher语句填充至POST的数据段中
1100 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, rootString.c_str());
1101 |
1102 | //执行DELETE请求
1103 | CURLcode res = curl_easy_perform(curl);
1104 |
1105 | //根据执行结果返回执行结果或抛出异常
1106 | if (res != 0)
1107 | {
1108 | //post请求执行失败,抛出异常
1109 | throw "POST REQUEST EXECUTION IS FAILED!";
1110 | }
1111 | else
1112 | {
1113 | //对返回数据的协议状态进行检查
1114 | std::string statusCode = Kit::getStatusCode(this->responseHeaderString);
1115 |
1116 | if (statusCode == "201")
1117 | {
1118 | //添加成功
1119 | Json::Reader reader;
1120 | Json::Value responseJson;
1121 | Json::Value metaData;
1122 |
1123 | reader.parse(this->responseString, responseJson);
1124 |
1125 | this->responseHeaderString = "";
1126 | this->responseString = "";
1127 |
1128 | metaData = responseJson["metadata"];
1129 |
1130 | relationship = responseJson["data"];
1131 | relationship["_id"] = metaData["id"];
1132 | relationship["_type"] = metaData["type"];
1133 |
1134 | return true;
1135 | }
1136 | else if (statusCode == "400")
1137 | {
1138 | this->responseHeaderString = "";
1139 | this->responseString = "";
1140 |
1141 | //终端节点未找到
1142 | relationship = Json::nullValue;
1143 |
1144 | return false;
1145 | }
1146 | else if (statusCode == "404")
1147 | {
1148 | this->responseHeaderString = "";
1149 | this->responseString = "";
1150 |
1151 | //始端节点未找到
1152 | relationship = Json::nullValue;
1153 |
1154 | return false;
1155 | }
1156 | else
1157 | {
1158 | this->responseHeaderString = "";
1159 | this->responseString = "";
1160 |
1161 | //解析失败,抛出异常
1162 | throw "RESPONSE STATUS IS ERROR!";
1163 | }
1164 | }
1165 | }
1166 | else
1167 | {
1168 | throw "CURL EASY INIT IS FAILED!";
1169 | }
1170 | };
1171 |
1172 | bool Neo4jAPI::insertRelationship(unsigned long long int rootNodeID, unsigned long long int otherNodeID, std::string typeName, Json::Value &relationship)
1173 | {
1174 | Json::Value properties;
1175 | return Neo4jAPI::insertRelationship(rootNodeID, otherNodeID, typeName, properties, relationship);
1176 | };
1177 |
1178 | bool Neo4jAPI::insertRelationship(unsigned long long int rootNodeID, unsigned long long int otherNodeID, std::string typeName)
1179 | {
1180 | Json::Value properties;
1181 | Json::Value relationship;
1182 | return Neo4jAPI::insertRelationship(rootNodeID, otherNodeID, typeName, properties, relationship);
1183 | };
1184 |
1185 | bool Neo4jAPI::deleteRelationship(unsigned long long int relationshipID)
1186 | {
1187 | if (this->curl)
1188 | {
1189 | std::stringstream sstream;
1190 | sstream << relationshipID;
1191 | std::string relationshipIDString;
1192 | sstream >> relationshipIDString;
1193 | sstream.clear();
1194 |
1195 | std::string httpUrl = "http://" + this->host + ":" + this->port + "/db/data/relationship/" + relationshipIDString;
1196 |
1197 | //指定访问点
1198 | curl_easy_setopt(this->curl, CURLOPT_URL, httpUrl.c_str());
1199 | //指定请求方式为DELETE
1200 | curl_easy_setopt(this->curl, CURLOPT_CUSTOMREQUEST, "DELETE");
1201 |
1202 | //执行DELETE请求
1203 | CURLcode res = curl_easy_perform(curl);
1204 |
1205 | //根据执行结果返回执行结果或抛出异常
1206 | if (res != 0)
1207 | {
1208 | //post请求执行失败,抛出异常
1209 | throw "DELETE REQUEST EXECUTION IS FAILED!";
1210 | }
1211 | else
1212 | {
1213 | //对返回数据的协议状态进行检查
1214 | std::string statusCode = Kit::getStatusCode(this->responseHeaderString);
1215 |
1216 | this->responseHeaderString = "";
1217 | this->responseString = "";
1218 |
1219 | /*
1220 | * 此处与文档不同,文档中删除关系成功后返回204,但实际返回的却是200
1221 | */
1222 |
1223 | if (statusCode == "204" || statusCode == "200")
1224 | {
1225 | //删除成功
1226 | return true;
1227 | }
1228 | else if (statusCode == "404")
1229 | {
1230 | //未找到该关系
1231 | return false;
1232 | }
1233 | else
1234 | {
1235 | //解析失败,抛出异常
1236 | throw "RESPONSE STATUS IS ERROR!";
1237 | }
1238 | }
1239 | }
1240 | else
1241 | {
1242 | throw "CURL EASY INIT IS FAILED!";
1243 | }
1244 | };
1245 |
1246 | unsigned long long int Neo4jAPI::deleteRelationshipsOfOneNode(unsigned long long int nodeID, std::string type)
1247 | {
1248 | Json::Value relationshipList;
1249 | Json::Value relationship;
1250 | int count = 0;
1251 |
1252 | if (type == "in")
1253 | {
1254 | relationshipList = this->getRelationshipsOfOneNode(nodeID, "in");
1255 | }
1256 | else if (type == "out")
1257 | {
1258 | relationshipList = this->getRelationshipsOfOneNode(nodeID, "out");
1259 | }
1260 | else
1261 | {
1262 | relationshipList = this->getRelationshipsOfOneNode(nodeID, "all");
1263 | }
1264 |
1265 | for (int i = 0; ideleteRelationship(relationship["_id"].asLargestUInt()))
1270 | {
1271 | count++;
1272 | }
1273 | }
1274 |
1275 | return count;
1276 | };
1277 |
1278 | unsigned long long int Neo4jAPI::deleteAllRelationshipsOfOneNode(unsigned long long int nodeID)
1279 | {
1280 | return this->deleteRelationshipsOfOneNode(nodeID, "all");
1281 | };
1282 |
1283 | unsigned long long int Neo4jAPI::deleteAllOutgoingRelationshipsOfOneNode(unsigned long long int nodeID)
1284 | {
1285 | return this->deleteRelationshipsOfOneNode(nodeID, "out");
1286 | };
1287 |
1288 | unsigned long long int Neo4jAPI::deleteAllIncomingRelationshipsOfOneNode(unsigned long long int nodeID)
1289 | {
1290 | return this->deleteRelationshipsOfOneNode(nodeID, "in");
1291 | };
1292 |
1293 | bool Neo4jAPI::getRelationship(unsigned long long int relationshipID, Json::Value &relationship)
1294 | {
1295 | if (this->curl)
1296 | {
1297 | std::stringstream sstream;
1298 | sstream << relationshipID;
1299 | std::string relationshipIDString;
1300 | sstream >> relationshipIDString;
1301 | sstream.clear();
1302 |
1303 | std::string httpUrl = "http://" + this->host + ":" + this->port + "/db/data/relationship/" + relationshipIDString;
1304 |
1305 | //指定访问点
1306 | curl_easy_setopt(this->curl, CURLOPT_URL, httpUrl.c_str());
1307 |
1308 | //执行GET请求
1309 | CURLcode res = curl_easy_perform(curl);
1310 |
1311 | //根据执行结果返回执行结果或抛出异常
1312 | if (res != 0)
1313 | {
1314 | //post请求执行失败,抛出异常
1315 | throw "GET REQUEST EXECUTION IS FAILED!";
1316 | }
1317 | else
1318 | {
1319 | //对返回数据的协议状态进行检查
1320 | std::string statusCode = Kit::getStatusCode(this->responseHeaderString);
1321 |
1322 | if (statusCode == "200")
1323 | {
1324 | //成功获得该关系
1325 | //添加成功
1326 | Json::Reader reader;
1327 | Json::Value responseJson;
1328 | Json::Value metaData;
1329 |
1330 | reader.parse(this->responseString, responseJson);
1331 |
1332 | this->responseHeaderString = "";
1333 | this->responseString = "";
1334 |
1335 | metaData = responseJson["metadata"];
1336 |
1337 | relationship = responseJson["data"];
1338 | relationship["_id"] = metaData["id"];
1339 | relationship["_type"] = metaData["type"];
1340 | relationship["_start"] = Kit::getNodeOrRelationshipID(responseJson["start"].asString());
1341 | relationship["_end"] = Kit::getNodeOrRelationshipID(responseJson["end"].asString());
1342 |
1343 | return true;
1344 | }
1345 | else if (statusCode == "404")
1346 | {
1347 | this->responseHeaderString = "";
1348 | this->responseString = "";
1349 |
1350 | //未找到该关系
1351 | return false;
1352 | }
1353 | else
1354 | {
1355 | this->responseHeaderString = "";
1356 | this->responseString = "";
1357 |
1358 | //解析失败,抛出异常
1359 | throw "RESPONSE PARSE IS ERROR!";
1360 | }
1361 | }
1362 | }
1363 | else
1364 | {
1365 | throw "CURL EASY INIT IS FAILED!";
1366 | }
1367 | };
1368 |
1369 | Json::Value Neo4jAPI::getRelationshipsOfOneNode(unsigned long long int nodeID, std::string type)
1370 | {
1371 | if (this->curl)
1372 | {
1373 | if (type != "all" && type != "in" && type != "out")
1374 | {
1375 | type = "all";
1376 | }
1377 |
1378 | std::stringstream sstream;
1379 | sstream << nodeID;
1380 | std::string nodeIDString;
1381 | sstream >> nodeIDString;
1382 | sstream.clear();
1383 |
1384 | std::string httpUrl = "http://" + this->host + ":" + this->port + "/db/data/node/" + nodeIDString + "/relationships/" + type;
1385 |
1386 | //指定请求方式为GET
1387 | //若不设置该项,默认执行什么方法????
1388 | curl_easy_setopt(this->curl, CURLOPT_CUSTOMREQUEST, "GET");
1389 |
1390 | //指定访问点
1391 | curl_easy_setopt(this->curl, CURLOPT_URL, httpUrl.c_str());
1392 |
1393 | //执行GET请求
1394 | CURLcode res = curl_easy_perform(curl);
1395 |
1396 | //根据执行结果返回执行结果或抛出异常
1397 | if (res != 0)
1398 | {
1399 | //post请求执行失败,抛出异常
1400 | throw "GET REQUEST EXECUTION IS FAILED!";
1401 | }
1402 | else
1403 | {
1404 | //对返回数据的协议状态进行检查
1405 | std::string statusCode = Kit::getStatusCode(this->responseHeaderString);
1406 |
1407 | if (statusCode == "200")
1408 | {
1409 | //获得成功
1410 | Json::Reader reader;
1411 | Json::Value relationshipInfoList;
1412 | Json::Value relationshipInfo;
1413 | Json::Value relationshipList;
1414 | Json::Value relationship;
1415 |
1416 | Json::Value metadata;
1417 |
1418 | reader.parse(this->responseString, relationshipInfoList);
1419 |
1420 | this->responseHeaderString = "";
1421 | this->responseString = "";
1422 |
1423 | for (int i = 0; i < relationshipInfoList.size(); i++)
1424 | {
1425 | relationshipInfo = relationshipInfoList[i];
1426 |
1427 | metadata = relationshipInfo["metadata"];
1428 |
1429 | relationship = relationshipInfo["data"];
1430 | relationship["_id"] = metadata["id"];
1431 | relationship["_type"] = metadata["type"];
1432 | relationship["_start"] = Kit::getNodeOrRelationshipID(relationshipInfo["start"].asString());
1433 | relationship["_end"] = Kit::getNodeOrRelationshipID(relationshipInfo["end"].asString());
1434 |
1435 | relationshipList.append(relationship);
1436 | }
1437 |
1438 | return relationshipList;
1439 | }
1440 | else
1441 | {
1442 | this->responseHeaderString = "";
1443 | this->responseString = "";
1444 |
1445 | //解析失败,抛出异常
1446 | throw "RESPONSE PARSE IS ERROR!";
1447 | }
1448 | }
1449 | }
1450 | else
1451 | {
1452 | throw "CURL EASY INIT IS FAILED!";
1453 | }
1454 | };
1455 |
1456 | Json::Value Neo4jAPI::getAllRelationshipsOfOneNode(unsigned long long int nodeID)
1457 | {
1458 | return this->getRelationshipsOfOneNode(nodeID, "all");
1459 | };
1460 |
1461 | Json::Value Neo4jAPI::getAllOutgoingRelationshipsOfOneNode(unsigned long long int nodeID)
1462 | {
1463 | return this->getRelationshipsOfOneNode(nodeID, "out");
1464 | };
1465 |
1466 | Json::Value Neo4jAPI::getAllIncomingRelationshipsOfOneNode(unsigned long long int nodeID)
1467 | {
1468 | return this->getRelationshipsOfOneNode(nodeID, "in");
1469 | };
1470 |
1471 | // Json::Value Neo4jAPI::selectRelationshipsByTypeAndProperties(std::string type, Json::Value &properties)
1472 | // {
1473 | // if (this->curl)
1474 | // {
1475 | // std::string httpUrlForTransaction = "http://" + this->host + ":" + this->port + "/db/data/transaction/commit";
1476 | //
1477 | // //指定访问点
1478 | // curl_easy_setopt(this->curl, CURLOPT_URL, httpUrlForTransaction.c_str());
1479 | //
1480 | // //通过Json构建Cypher语句的查询字符串
1481 | // Json::Value statement;
1482 | // Json::Value statements;
1483 | // Json::Value root;
1484 | // Json::FastWriter writer;
1485 | // std::string cypher = "", whereString = Neo4jDatabaseInterfaceKit::getWhereString("data", properties), rootString;
1486 | //
1487 | // if (label != "")
1488 | // {
1489 | // cypher = "MATCH (data:" + label + ")";
1490 | // }
1491 | // else
1492 | // {
1493 | // cypher = "MATCH (data)";
1494 | // }
1495 | //
1496 | // if (whereString != "")
1497 | // {
1498 | // cypher += " WHERE " + whereString;
1499 | // }
1500 | //
1501 | // cypher += " RETURN data";
1502 | //
1503 | // statement["statement"] = cypher;
1504 | // statement["parameters"] = properties;
1505 | // statement["resultDataContents"].append("REST");
1506 | //
1507 | // statements.append(statement);
1508 | //
1509 | // root["statements"] = statements;
1510 | // rootString = writer.write(root);
1511 | //
1512 | // //指定请求方式为POST
1513 | // curl_easy_setopt(this->curl, CURLOPT_POST, 1);
1514 | // //将Cypher语句填充至POST的数据段中
1515 | // curl_easy_setopt(curl, CURLOPT_POSTFIELDS, rootString.c_str());
1516 | //
1517 | // //执行POST请求
1518 | // CURLcode res = curl_easy_perform(curl);
1519 | //
1520 | // //根据执行结果返回执行结果或抛出异常
1521 | // if (res != 0)
1522 | // {
1523 | // //post请求执行失败,抛出异常
1524 | // throw exception::DatabaseException(4, this->getHost(), this->getPort(), this->getUser(), this->getPassword(), "");
1525 | // }
1526 | // else
1527 | // {
1528 | // //对返回数据的协议状态进行检查
1529 | // std::string statusCode = Neo4jDatabaseInterfaceKit::getStatusCode(this->responseHeaderString);
1530 | //
1531 | // if (statusCode != "200")
1532 | // {
1533 | // this->responseHeaderString = "";
1534 | // this->responseString = "";
1535 | //
1536 | // throw exception::DatabaseException(5, this->getHost(), this->getPort(), this->getUser(), this->getPassword(), "");
1537 | // }
1538 | //
1539 | // //成功返回执行结果,对结果进行分析处理
1540 | //
1541 | // Json::Value responseJson;
1542 | // Json::Value results;
1543 | // Json::Value errors;
1544 | // Json::Reader reader;
1545 | //
1546 | // //将返回字符串解析为Json对象
1547 | // if (reader.parse(this->responseString, responseJson))
1548 | // {
1549 | // this->responseHeaderString = "";
1550 | // this->responseString = "";
1551 |
1552 | // //取出其中的错误部分
1553 | // errors = responseJson["errors"];
1554 | //
1555 | // //判断语句执行是否发生错误
1556 | // if (errors.size() != 0)
1557 | // {
1558 | // //若错误部分不为空,抛出异常
1559 | // throw exception::DatabaseException(42, this->getHost(), this->getPort(), this->getUser(), this->getPassword(), "", errors[0].toStyledString());
1560 | // }
1561 | // else
1562 | // {
1563 | // //未发生错误,提取查询结果
1564 | // results = responseJson["results"];
1565 | //
1566 | // //判断查询结果是否为空
1567 | // if (results.size() == 1)
1568 | // {
1569 | // //不为空,返回结果
1570 | // Json::Value result = results[0];
1571 | // Json::Value data = result["data"];
1572 | // Json::Value rests;
1573 | // Json::Value rest;
1574 | // Json::Value node;
1575 | // Json::Value metadata;
1576 | // Json::Value nodeList;
1577 | //
1578 | // for (int i = 0; i < data.size(); i++)
1579 | // {
1580 | // rests = data[i]["rest"];
1581 | // rest = rests[0];
1582 | // node = rest["data"];
1583 | // metadata = rest["metadata"];
1584 | // node["_id"] = metadata["id"];
1585 | // node["_labels"] = metadata["labels"];
1586 | //
1587 | // nodeList.append(node);
1588 | // }
1589 | //
1590 | // return nodeList;
1591 | // }
1592 | // else
1593 | // {
1594 | // //为空或多于一条,格式错误,抛出异常
1595 | // throw exception::DatabaseException(41, this->getHost(), this->getPort(), this->getUser(), this->getPassword(), "");
1596 | // }
1597 | // }
1598 | // }
1599 | // else
1600 | // {
1601 | // this->responseHeaderString = "";
1602 | // this->responseString = "";
1603 | //
1604 | // //解析失败,抛出异常
1605 | // throw exception::DatabaseException(40, this->getHost(), this->getPort(), this->getUser(), this->getPassword(), "");
1606 | // }
1607 | // }
1608 | // }
1609 | // else
1610 | // {
1611 | // throw "CURL EASY INIT IS FAILED!";
1612 | // }
1613 | //
1614 | // };
1615 |
1616 | Json::Value Neo4jAPI::getRelationsBetweenTwoNodes(unsigned long long int fromNodeID, unsigned long long int toNodeID, std::string type)
1617 | {
1618 | std::stringstream sstream;
1619 | std::string fromNodeIDString, toNodeIDString;
1620 | sstream << fromNodeID;
1621 | sstream >> fromNodeIDString;
1622 | sstream.clear();
1623 | sstream << toNodeID;
1624 | sstream >> toNodeIDString;
1625 | sstream.clear();
1626 |
1627 | std::string cypher;
1628 |
1629 | if (type == "")
1630 | {
1631 | cypher = "MATCH (m)-[data]->(n) WHERE id(m)=" + fromNodeIDString + " AND id(n)=" + toNodeIDString +" RETURN id(data), type(data), data";
1632 | }
1633 | else
1634 | {
1635 | cypher = "MATCH (m)-[data]->(n) WHERE id(m)=" + fromNodeIDString + " AND id(n)=" + toNodeIDString + " AND type(data)=" + type + " RETURN id(data), type(data), data";
1636 | }
1637 | //解析过程是否发生异常严重依赖返回的数据,该怎么看待和处理?
1638 | Json::Value result = this->cypherQuery(cypher);
1639 | Json::Value data = result["data"];
1640 | Json::Value relations;
1641 |
1642 | for (auto i = 0; i < data.size(); i++)
1643 | {
1644 | Json::Value relation, row = data[0]["row"];
1645 |
1646 | relation["_id"] = row[0];
1647 | relation["_type"] = row[1];
1648 | relation["properties"] = row[2];
1649 |
1650 | relations[i] = relation;
1651 | }
1652 |
1653 | return relations;
1654 | };
1655 |
1656 | bool Neo4jAPI::replaceRelationshipProperties(unsigned long long int relationshipID, Json::Value &properties)
1657 | {
1658 | if (this->curl)
1659 | {
1660 | std::stringstream sstream;
1661 | sstream << relationshipID;
1662 | std::string relationshipIDString;
1663 | sstream >> relationshipIDString;
1664 | sstream.clear();
1665 |
1666 | std::string httpUrl = "http://" + this->host + ":" + this->port + "/db/data/relationship/" + relationshipIDString + "/properties";
1667 |
1668 | //指定访问点
1669 | curl_easy_setopt(this->curl, CURLOPT_URL, httpUrl.c_str());
1670 |
1671 | Json::FastWriter writer;
1672 |
1673 | std::string propertiesString = writer.write(properties);
1674 |
1675 | //指定请求方式为PUT
1676 | curl_easy_setopt(this->curl, CURLOPT_CUSTOMREQUEST, "PUT");
1677 |
1678 | /*
1679 | * 指定请求方式为PUT,但却将数据放进了POSTFIELDS,这样是稳定的吗?
1680 | */
1681 |
1682 | //将Cypher语句填充至POST的数据段中
1683 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, propertiesString.c_str());
1684 |
1685 | //执行PUT请求
1686 | CURLcode res = curl_easy_perform(curl);
1687 |
1688 | //恢复请求方式
1689 | curl_easy_setopt(this->curl, CURLOPT_CUSTOMREQUEST, NULL);
1690 |
1691 | //根据执行结果返回执行结果或抛出异常
1692 | if (res != 0)
1693 | {
1694 | //post请求执行失败,抛出异常
1695 | throw "PUT REQUEST EXECUTION IS FAILED!";
1696 | }
1697 | else
1698 | {
1699 | //对返回数据的协议状态进行检查
1700 | std::string statusCode = Kit::getStatusCode(this->responseHeaderString);
1701 |
1702 | this->responseHeaderString = "";
1703 | this->responseString = "";
1704 |
1705 | if (statusCode == "204")
1706 | {
1707 | return true;
1708 | }
1709 | else if (statusCode == "404")
1710 | {
1711 | return false;
1712 | }
1713 | else
1714 | {
1715 | //解析失败,抛出异常
1716 | throw "RESPONSE STATUS IS ERROR!";
1717 | }
1718 | }
1719 | }
1720 | else
1721 | {
1722 | throw "CURL EASY INIT IS FAILED!";
1723 | }
1724 | };
1725 |
1726 | Neo4jAPI::~Neo4jAPI()
1727 | {
1728 | //清理headers和curl
1729 | if (this->headers != NULL)
1730 | {
1731 | curl_slist_free_all(this->headers);
1732 | this->headers = NULL;
1733 | }
1734 | if (this->curl)
1735 | {
1736 | curl_easy_cleanup(this->curl);
1737 | this->curl = NULL;
1738 | }
1739 |
1740 | //删除该数据库接口占用的数据库驱动
1741 | this->database->deleteNeo4j();
1742 | };
1743 |
1744 | /*
1745 | * 私有方法
1746 | */
1747 |
1748 | size_t Neo4jAPI::responseHeaderHandeler(char *buffer, size_t size, size_t nitems, void *userdata)
1749 | {
1750 | //计算本次收到的数据长度
1751 | size_t responseHeaderDataLength = size * nitems;
1752 | //根据算出的数据长度建立字节数组用于接收本次数据
1753 | char* responseHeaderData = new char[responseHeaderDataLength];
1754 |
1755 | //若字节数组建立失败,返回0触发接受失败,停止接受
1756 | if(NULL == responseHeaderData)
1757 | {
1758 | return 0;
1759 | }
1760 |
1761 | //获取最终数据存放的位置
1762 | std::string* responseHeaderDataPtr = (std::string*)userdata;
1763 |
1764 | //接收本次数据
1765 | memcpy(responseHeaderData, buffer, responseHeaderDataLength);
1766 |
1767 | //将本次接收到的数据存储至最终的数据位置
1768 | *responseHeaderDataPtr = *responseHeaderDataPtr + std::string(responseHeaderData, responseHeaderDataLength);
1769 |
1770 | //释放用于存储本次接收到的数据的字节数组
1771 | delete[] responseHeaderData;
1772 |
1773 | //返回本次接收到的数据的长度
1774 | return responseHeaderDataLength;
1775 | };
1776 |
1777 | size_t Neo4jAPI::responseHandeler(char *ptr, size_t size, size_t nmemb, void *userdata)
1778 | {
1779 | //计算本次收到的数据长度
1780 | size_t responseDataLength = size * nmemb;
1781 | //根据算出的数据长度建立字节数组用于接收本次数据
1782 | char* responseData = new char[responseDataLength];
1783 |
1784 | //若字节数组建立失败,返回0触发接受失败,停止接受
1785 | if(NULL == responseData)
1786 | {
1787 | return 0;
1788 | }
1789 |
1790 | //获取最终数据存放的位置
1791 | std::string* responseDataPtr = (std::string*)userdata;
1792 |
1793 | //接收本次数据
1794 | memcpy(responseData, ptr, responseDataLength);
1795 |
1796 | //将本次接收到的数据存储至最终的数据位置
1797 | *responseDataPtr = *responseDataPtr + std::string(responseData, responseDataLength);
1798 |
1799 | //释放用于存储本次接收到的数据的字节数组
1800 | delete[] responseData;
1801 |
1802 | //返回本次接收到的数据的长度
1803 | return responseDataLength;
1804 | };
1805 | }
1806 |
--------------------------------------------------------------------------------
/api.hpp:
--------------------------------------------------------------------------------
1 | //
2 | // api.hpp
3 | // Neo4j-cpp-driver
4 | //
5 | // Created by skyblue on 2017/7/9.
6 | // Copyright © 2017年 skyblue. All rights reserved.
7 | //
8 |
9 | #ifndef api_hpp
10 | #define api_hpp
11 |
12 | #include
13 | #include
14 |
15 | #include "curl/curl.h"
16 | #include "json/json.h"
17 |
18 | #include "./database.hpp"
19 |
20 | namespace neo4jDriver
21 | {
22 | class Neo4jAPI
23 | {
24 | public:
25 |
26 | /****************/
27 | /* 构造方法 */
28 | /****************/
29 |
30 | //构造方法
31 | Neo4jAPI(std::shared_ptr database);
32 |
33 | //构造方法
34 | Neo4jAPI(std::shared_ptr database, std::string host, std::string port, std::string user, std::string password);
35 |
36 | /****************/
37 | /* 基本信息及操作 */
38 | /****************/
39 |
40 | std::string getHost();
41 |
42 | std::string getPort();
43 |
44 | std::string getUser();
45 |
46 | std::string getPassword();
47 |
48 | void connectDatabase();
49 |
50 | void closeDatabase();
51 |
52 | /****************/
53 | /* 驱动接口 */
54 | /* 点部分 */
55 | /****************/
56 |
57 | //执行Cypher语句
58 | Json::Value cypherQuery(std::string cypher, Json::Value properties = Json::nullValue);
59 |
60 | //创建点(单Label)
61 | Json::Value createNode(const Json::Value &properties, const std::string &label);
62 |
63 | //创建点(多Label)
64 | Json::Value createNode(const Json::Value &properties, const std::vector &labels);
65 |
66 | //根据点ID删除点
67 | bool deleteNode(unsigned long long int nodeID);
68 |
69 | //根据点ID删除点和该点的全部关系
70 | /*
71 | * 这个版本有问题,可能出现删除了全部边后因为网络问题没有将点删除的问题,健壮性依赖于网络
72 | * 改进方案,使用事务处理
73 | */
74 | bool deleteNodeAndAllRelationshipsOfTheNode(unsigned long long int nodeID);
75 |
76 | //根据点Label和属性删除点(单Label)
77 | unsigned long long int deleteNodeByLabelAndProperties(std::string label, Json::Value &properties);
78 |
79 | //根据点Label和属性删除点(多Label)
80 | unsigned long long int deleteNodeByLabelsAndProperties(std::vector &labels, Json::Value &properties);
81 |
82 | //获得指定ID的点
83 | bool getNode(unsigned long long int nodeID, Json::Value &node);
84 |
85 | /*
86 | * 查询指定Label和属性的点(单Label)
87 | */
88 | Json::Value selectNodesByLabelAndProperties(std::string label, Json::Value &properties);
89 |
90 | /*
91 | * 查询指定Label和属性的点(多Label)
92 | */
93 | Json::Value selectNodesByLabelsAndProperties(std::vector &labels, Json::Value &properties);
94 |
95 | /*
96 | * 查询和指定点存在指定关系的点
97 | */
98 | Json::Value selectNodesByAnotherLinkedNode(std::string selectedLabel, Json::Value &selectedProperties, std::string relationTypeName, Json::Value &relationProperties, std::string linkedLabel, Json::Value &linkedProperties);
99 |
100 | Json::Value selectNodesByAnotherLinkedNode(std::string selectedLabel, Json::Value &selectedProperties, std::string relationTypeName, Json::Value &relationProperties, unsigned long long int linkedNodeID);
101 |
102 | /*
103 | * 更新点的属性
104 | * 该方法只会修改properties中存在的属性,点的其他属性仍将保留
105 | */
106 | bool updateNodeByID(unsigned long long int nodeID, Json::Value &properties);
107 |
108 | /*
109 | * 替换点的属性
110 | * 该方法会用properties替换点的全部属性,properties中没有的属性将丢失
111 | */
112 | bool replaceNodeByID(unsigned long long int nodeID, Json::Value &properties);
113 |
114 | /****************/
115 | /* 驱动接口 */
116 | /* 边部分 */
117 | /****************/
118 |
119 | //根据始点和终点的ID插入两点的关系
120 | //返回值表示是否插入成功,关系本身由引用参数返回
121 | bool insertRelationship(unsigned long long int rootNodeID, unsigned long long int otherNodeID, std::string typeName, Json::Value &properties, Json::Value &relationship);
122 |
123 | //根据始点和终点的ID插入两点的关系(关系不含属性)
124 | //返回值表示是否插入成功,关系本身由引用参数返回
125 | bool insertRelationship(unsigned long long int rootNodeID, unsigned long long int otherNodeID, std::string typeName, Json::Value &relationship);
126 |
127 | //根据始点和终点的ID插入两点的关系(关系不含属性)
128 | //返回值表示是否插入成功,不返回关系
129 | bool insertRelationship(unsigned long long int rootNodeID, unsigned long long int otherNodeID, std::string typeName);
130 |
131 | //删除指定ID的关系
132 | bool deleteRelationship(unsigned long long int relationshipID);
133 |
134 | //删除指定ID的点的指定类型的边
135 | unsigned long long int deleteRelationshipsOfOneNode(unsigned long long int nodeID, std::string type);
136 |
137 | //删除指定ID的点的全部边
138 | unsigned long long int deleteAllRelationshipsOfOneNode(unsigned long long int nodeID);
139 |
140 | /*
141 | * 删除指定ID的点的全部出边
142 | */
143 | unsigned long long int deleteAllOutgoingRelationshipsOfOneNode(unsigned long long int nodeID);
144 |
145 | /*
146 | * 删除指定ID的点的全部入边
147 | */
148 | unsigned long long int deleteAllIncomingRelationshipsOfOneNode(unsigned long long int nodeID);
149 |
150 | /*
151 | * 获得指定ID的关系
152 | * 返回值表示是否找到,关系本身由引用参数返回
153 | */
154 | bool getRelationship(unsigned long long int relationshipID, Json::Value &relationship);
155 |
156 | /*
157 | * 获得指定ID的点的指定类型的所有边
158 | */
159 | Json::Value getRelationshipsOfOneNode(unsigned long long int nodeID, std::string type);
160 |
161 | /*
162 | * 获得指定ID的点的所有边
163 | */
164 | Json::Value getAllRelationshipsOfOneNode(unsigned long long int nodeID);
165 |
166 | /*
167 | * 获得指定ID的点的所有出边
168 | */
169 | Json::Value getAllOutgoingRelationshipsOfOneNode(unsigned long long int nodeID);
170 |
171 | /*
172 | * 获得指定ID的点的所有入边
173 | */
174 | Json::Value getAllIncomingRelationshipsOfOneNode(unsigned long long int nodeID);
175 |
176 | /*
177 | * 查询指定type和属性的关系
178 | */
179 | // Json::Value selectRelationshipsByTypeAndProperties(std::string type, Json::Value &properties);
180 |
181 | //获得指定ID的起点和终点之间的全部边
182 | Json::Value getRelationsBetweenTwoNodes(unsigned long long int fromNodeID, unsigned long long int toNodeID, std::string type = "");
183 |
184 | /*
185 | * 更换关系的属性
186 | */
187 | bool replaceRelationshipProperties(unsigned long long int relationshipID, Json::Value &properties);
188 |
189 | /*
190 | * 析构方法
191 | */
192 | ~Neo4jAPI();
193 |
194 | private:
195 | std::shared_ptr database;
196 | std::string host, port, user, password;
197 | CURL* curl;
198 | struct curl_slist* headers;
199 | std::string responseString;
200 | std::string responseHeaderString;
201 |
202 | /*
203 | * 对HTTP协议返回的协议头进行处理的回调方法
204 | */
205 | static size_t responseHeaderHandeler(char *buffer, size_t size, size_t nitems, void *userdata);
206 |
207 | /*
208 | * 对HTTP协议返回的数据进行处理的回调方法
209 | */
210 | static size_t responseHandeler(char *ptr, size_t size, size_t nmemb, void *userdata);
211 | };
212 | }
213 |
214 | #endif /* api_hpp */
215 |
--------------------------------------------------------------------------------
/base64.hpp:
--------------------------------------------------------------------------------
1 | //
2 | // base64.hpp
3 | // Neo4j-cpp-driver
4 | //
5 | // Created by skyblue on 2017/7/9.
6 | // Copyright © 2017年 skyblue. All rights reserved.
7 | //
8 |
9 | #ifndef base64_hpp
10 | #define base64_hpp
11 |
12 | #include
13 |
14 | namespace neo4jDriver
15 | {
16 | const char kBase64Alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
17 | "abcdefghijklmnopqrstuvwxyz"
18 | "0123456789+/";
19 |
20 | class Base64
21 | {
22 | public:
23 | static bool Encode(const std::string &in, std::string *out) {
24 | int i = 0, j = 0;
25 | size_t enc_len = 0;
26 | unsigned char a3[3];
27 | unsigned char a4[4];
28 |
29 | out->resize(EncodedLength(in));
30 |
31 | int input_len = in.size();
32 | std::string::const_iterator input = in.begin();
33 |
34 | while (input_len--) {
35 | a3[i++] = *(input++);
36 | if (i == 3) {
37 | a3_to_a4(a4, a3);
38 |
39 | for (i = 0; i < 4; i++) {
40 | (*out)[enc_len++] = kBase64Alphabet[a4[i]];
41 | }
42 |
43 | i = 0;
44 | }
45 | }
46 |
47 | if (i) {
48 | for (j = i; j < 3; j++) {
49 | a3[j] = '\0';
50 | }
51 |
52 | a3_to_a4(a4, a3);
53 |
54 | for (j = 0; j < i + 1; j++) {
55 | (*out)[enc_len++] = kBase64Alphabet[a4[j]];
56 | }
57 |
58 | while ((i++ < 3)) {
59 | (*out)[enc_len++] = '=';
60 | }
61 | }
62 |
63 | return (enc_len == out->size());
64 | }
65 |
66 | static bool Encode(const char *input, size_t input_length, char *out, size_t out_length) {
67 | int i = 0, j = 0;
68 | char *out_begin = out;
69 | unsigned char a3[3];
70 | unsigned char a4[4];
71 |
72 | size_t encoded_length = EncodedLength(input_length);
73 |
74 | if (out_length < encoded_length) return false;
75 |
76 | while (input_length--) {
77 | a3[i++] = *input++;
78 | if (i == 3) {
79 | a3_to_a4(a4, a3);
80 |
81 | for (i = 0; i < 4; i++) {
82 | *out++ = kBase64Alphabet[a4[i]];
83 | }
84 |
85 | i = 0;
86 | }
87 | }
88 |
89 | if (i) {
90 | for (j = i; j < 3; j++) {
91 | a3[j] = '\0';
92 | }
93 |
94 | a3_to_a4(a4, a3);
95 |
96 | for (j = 0; j < i + 1; j++) {
97 | *out++ = kBase64Alphabet[a4[j]];
98 | }
99 |
100 | while ((i++ < 3)) {
101 | *out++ = '=';
102 | }
103 | }
104 |
105 | return (out == (out_begin + encoded_length));
106 | }
107 |
108 | static bool Decode(const std::string &in, std::string *out) {
109 | int i = 0, j = 0;
110 | size_t dec_len = 0;
111 | unsigned char a3[3];
112 | unsigned char a4[4];
113 |
114 | int input_len = in.size();
115 | std::string::const_iterator input = in.begin();
116 |
117 | out->resize(DecodedLength(in));
118 |
119 | while (input_len--) {
120 | if (*input == '=') {
121 | break;
122 | }
123 |
124 | a4[i++] = *(input++);
125 | if (i == 4) {
126 | for (i = 0; i <4; i++) {
127 | a4[i] = b64_lookup(a4[i]);
128 | }
129 |
130 | a4_to_a3(a3,a4);
131 |
132 | for (i = 0; i < 3; i++) {
133 | (*out)[dec_len++] = a3[i];
134 | }
135 |
136 | i = 0;
137 | }
138 | }
139 |
140 | if (i) {
141 | for (j = i; j < 4; j++) {
142 | a4[j] = '\0';
143 | }
144 |
145 | for (j = 0; j < 4; j++) {
146 | a4[j] = b64_lookup(a4[j]);
147 | }
148 |
149 | a4_to_a3(a3,a4);
150 |
151 | for (j = 0; j < i - 1; j++) {
152 | (*out)[dec_len++] = a3[j];
153 | }
154 | }
155 |
156 | return (dec_len == out->size());
157 | }
158 |
159 | static bool Decode(const char *input, size_t input_length, char *out, size_t out_length) {
160 | int i = 0, j = 0;
161 | char *out_begin = out;
162 | unsigned char a3[3];
163 | unsigned char a4[4];
164 |
165 | size_t decoded_length = DecodedLength(input, input_length);
166 |
167 | if (out_length < decoded_length) return false;
168 |
169 | while (input_length--) {
170 | if (*input == '=') {
171 | break;
172 | }
173 |
174 | a4[i++] = *(input++);
175 | if (i == 4) {
176 | for (i = 0; i <4; i++) {
177 | a4[i] = b64_lookup(a4[i]);
178 | }
179 |
180 | a4_to_a3(a3,a4);
181 |
182 | for (i = 0; i < 3; i++) {
183 | *out++ = a3[i];
184 | }
185 |
186 | i = 0;
187 | }
188 | }
189 |
190 | if (i) {
191 | for (j = i; j < 4; j++) {
192 | a4[j] = '\0';
193 | }
194 |
195 | for (j = 0; j < 4; j++) {
196 | a4[j] = b64_lookup(a4[j]);
197 | }
198 |
199 | a4_to_a3(a3,a4);
200 |
201 | for (j = 0; j < i - 1; j++) {
202 | *out++ = a3[j];
203 | }
204 | }
205 |
206 | return (out == (out_begin + decoded_length));
207 | }
208 |
209 | static int DecodedLength(const char *in, size_t in_length) {
210 | int numEq = 0;
211 |
212 | const char *in_end = in + in_length;
213 | while (*--in_end == '=') ++numEq;
214 |
215 | return ((6 * in_length) / 8) - numEq;
216 | }
217 |
218 | static int DecodedLength(const std::string &in) {
219 | int numEq = 0;
220 | int n = in.size();
221 |
222 | for (std::string::const_reverse_iterator it = in.rbegin(); *it == '='; ++it) {
223 | ++numEq;
224 | }
225 |
226 | return ((6 * n) / 8) - numEq;
227 | }
228 |
229 | inline static int EncodedLength(size_t length) {
230 | return (length + 2 - ((length + 2) % 3)) / 3 * 4;
231 | }
232 |
233 | inline static int EncodedLength(const std::string &in) {
234 | return EncodedLength(in.length());
235 | }
236 |
237 | inline static void StripPadding(std::string *in) {
238 | while (!in->empty() && *(in->rbegin()) == '=') in->resize(in->size() - 1);
239 | }
240 |
241 | private:
242 | static inline void a3_to_a4(unsigned char * a4, unsigned char * a3) {
243 | a4[0] = (a3[0] & 0xfc) >> 2;
244 | a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4);
245 | a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6);
246 | a4[3] = (a3[2] & 0x3f);
247 | }
248 |
249 | static inline void a4_to_a3(unsigned char * a3, unsigned char * a4) {
250 | a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4);
251 | a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2);
252 | a3[2] = ((a4[2] & 0x3) << 6) + a4[3];
253 | }
254 |
255 | static inline unsigned char b64_lookup(unsigned char c) {
256 | if(c >='A' && c <='Z') return c - 'A';
257 | if(c >='a' && c <='z') return c - 71;
258 | if(c >='0' && c <='9') return c + 4;
259 | if(c == '+') return 62;
260 | if(c == '/') return 63;
261 | return 255;
262 | }
263 | };
264 | }
265 |
266 | #endif /* base64_hpp */
267 |
--------------------------------------------------------------------------------
/database.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // database.cpp
3 | // Neo4j-cpp-driver
4 | //
5 | // Created by skyblue on 2017/7/9.
6 | // Copyright © 2017年 skyblue. All rights reserved.
7 | //
8 |
9 | #include "database.hpp"
10 |
11 | #include "/usr/local/opt/curl/include/curl/curl.h"
12 |
13 | namespace neo4jDriver
14 | {
15 | std::shared_ptr Neo4j::neo4j;
16 |
17 | Neo4j::Neo4j()
18 | {
19 | //执行curl库的初始化操作
20 | if (curl_global_init(CURL_GLOBAL_ALL) != 0)
21 | {
22 | throw "CURL GLOBAL INIT ERROR!";
23 | }
24 | };
25 |
26 | std::shared_ptr Neo4j::getNeo4j()
27 | {
28 | if (Neo4j::neo4j == nullptr)
29 | {
30 | Neo4j::neo4j = std::shared_ptr(new Neo4j::Neo4j());
31 | }
32 |
33 | return Neo4j::neo4j;
34 | };
35 |
36 | void Neo4j::deleteNeo4j()
37 | {
38 | if (Neo4j::neo4j.use_count() == 1)
39 | {
40 | Neo4j::neo4j.reset();
41 | }
42 | };
43 |
44 | Neo4j::~Neo4j()
45 | {
46 | curl_global_cleanup(); //curl库的清理操作
47 | };
48 | }
49 |
--------------------------------------------------------------------------------
/database.hpp:
--------------------------------------------------------------------------------
1 | //
2 | // neo4j.hpp
3 | // Neo4j-cpp-driver
4 | //
5 | // Created by skyblue on 2017/7/9.
6 | // Copyright © 2017年 skyblue. All rights reserved.
7 | //
8 |
9 | #ifndef neo4j_hpp
10 | #define neo4j_hpp
11 |
12 | #include
13 |
14 | namespace neo4jDriver
15 | {
16 | class Neo4j
17 | {
18 | public:
19 | static std::shared_ptr getNeo4j();
20 |
21 | void deleteNeo4j();
22 |
23 | ~Neo4j();
24 |
25 | private:
26 | Neo4j();
27 |
28 | static std::shared_ptr neo4j;
29 | };
30 | }
31 |
32 | #endif /* neo4j_hpp */
33 |
--------------------------------------------------------------------------------
/kit.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // kit.cpp
3 | // Neo4j-cpp-driver
4 | //
5 | // Created by skyblue on 2017/7/9.
6 | // Copyright © 2017年 skyblue. All rights reserved.
7 | //
8 |
9 | #include "kit.hpp"
10 |
11 | #include
12 |
13 | namespace neo4jDriver
14 | {
15 | //Neo4j工具包
16 |
17 | std::string Kit::getStatusCode(std::string httpHeader)
18 | {
19 | size_t begin = httpHeader.find_first_of(" ");
20 | std::string temp = httpHeader.substr(begin+1, httpHeader.length());
21 | size_t end = temp.find_first_of(" ");
22 | std::string statusCode = temp.substr(0, end);
23 | return statusCode;
24 | };
25 |
26 | std::string Kit::getWhereString(std::string fieldName, Json::Value &properties, std::string idFieldName)
27 | {
28 | return Kit::append(fieldName, properties, " AND ", idFieldName);
29 | };
30 |
31 | std::string Kit::getWhereString(std::string fieldName, std::string propertiesNamePrefix, Json::Value &properties, std::string idFieldName)
32 | {
33 | return Kit::append(fieldName, propertiesNamePrefix, properties, " AND ", idFieldName);
34 | };
35 |
36 | std::string Kit::getSetString(std::string fieldName, Json::Value &properties)
37 | {
38 | return Kit::append(fieldName, properties, ",");
39 | };
40 |
41 | std::string Kit::getLabelString(const std::vector &labels)
42 | {
43 | std::string labelsString = "";
44 |
45 | for (int i=0; i < labels.size(); i++)
46 | {
47 | if (i+1 < labels.size())
48 | {
49 | labelsString += labels[i] + ":";
50 | }
51 | else
52 | {
53 | labelsString += labels[i];
54 | }
55 | }
56 |
57 | return labelsString;
58 | };
59 |
60 | unsigned long long int Kit::getNodeOrRelationshipID(std::string nodeOrRelationshipSelf)
61 | {
62 | size_t id;
63 |
64 | size_t begin = nodeOrRelationshipSelf.find_last_of("/");
65 | std::string idString = nodeOrRelationshipSelf.substr(begin + 1, nodeOrRelationshipSelf.length());
66 |
67 | std::stringstream sstream;
68 | sstream << idString;
69 | sstream >> id;
70 | sstream.clear();
71 |
72 | return id;
73 | };
74 |
75 | /*
76 | * 私有方法
77 | */
78 |
79 | std::string Kit::append(std::string fieldName, Json::Value &properties, std::string appendToken, std::string idFieldName)
80 | {
81 | std::string parameters = "";
82 | bool isFirst = true;
83 |
84 | for (Json::ValueIterator i = properties.begin(); i != properties.end(); i++)
85 | {
86 | if (isFirst)
87 | {
88 | if (idFieldName == "" || (idFieldName != "" && i.name() != idFieldName))
89 | {
90 | parameters += fieldName + "." + i.name() + "={" + i.name() + "}";
91 | }
92 | else
93 | {
94 | parameters += "id(" + fieldName + ")={" + i.name() + "}";
95 | }
96 |
97 | isFirst = false;
98 | }
99 | else
100 | {
101 | if (idFieldName == "" || (idFieldName != "" && i.name() != idFieldName))
102 | {
103 | parameters += appendToken + fieldName + "." + i.name() + "={" + i.name() + "}";
104 | }
105 | else
106 | {
107 | parameters += appendToken + "id(" + fieldName + ")={" + i.name() + "}";
108 | }
109 | }
110 | }
111 |
112 | return parameters;
113 | };
114 |
115 | std::string Kit::append(std::string fieldName, std::string propertiesNamePrefix, Json::Value &properties, std::string appendToken, std::string idFieldName)
116 | {
117 | std::string parameters = "";
118 | bool isFirst = true;
119 |
120 | for (Json::ValueIterator i = properties.begin(); i != properties.end(); i++)
121 | {
122 | if (isFirst)
123 | {
124 | if (idFieldName == "" || (idFieldName != "" && i.name() != idFieldName))
125 | {
126 | parameters += fieldName + "." + i.name() + "={" + propertiesNamePrefix + i.name() + "}";
127 | }
128 | else
129 | {
130 | parameters += "id(" + fieldName + ")={" + propertiesNamePrefix + i.name() + "}";
131 | }
132 |
133 | isFirst = false;
134 | }
135 | else
136 | {
137 | if (idFieldName == "" || (idFieldName != "" && i.name() != idFieldName))
138 | {
139 | parameters += appendToken + fieldName + "." + i.name() + "={" + propertiesNamePrefix + i.name() + "}";
140 | }
141 | else
142 | {
143 | parameters += appendToken + "id(" + fieldName + ")={" + propertiesNamePrefix + i.name() + "}";
144 | }
145 | }
146 | }
147 |
148 | return parameters;
149 | };
150 | }
151 |
--------------------------------------------------------------------------------
/kit.hpp:
--------------------------------------------------------------------------------
1 | //
2 | // kit.hpp
3 | // Neo4j-cpp-driver
4 | //
5 | // Created by skyblue on 2017/7/9.
6 | // Copyright © 2017年 skyblue. All rights reserved.
7 | //
8 |
9 | #ifndef kit_hpp
10 | #define kit_hpp
11 |
12 | #include
13 | #include
14 |
15 | #include
16 |
17 | namespace neo4jDriver
18 | {
19 | class Kit
20 | {
21 | public:
22 |
23 | /*
24 | * 解析出HTTP协议头中的状态码
25 | */
26 | static std::string getStatusCode(std::string httpHeader);
27 |
28 | /*
29 | * 根据字段名和属性数组生成条件字符串
30 | */
31 | static std::string getWhereString(std::string fieldName, Json::Value &properties, std::string idFieldName = "");
32 |
33 | static std::string getWhereString(std::string fieldName, std::string propertiesNamePrefix, Json::Value &properties, std::string idFieldName = "");
34 |
35 | /*
36 | * 根据字段名和属性数组生成设置字符串
37 | */
38 | static std::string getSetString(std::string fieldName, Json::Value &properties);
39 |
40 | /*
41 | * 根据label数组生成label字符串
42 | */
43 | static std::string getLabelString(const std::vector &labels);
44 |
45 | static unsigned long long int getNodeOrRelationshipID(std::string nodeOrRelationshipSelf);
46 |
47 | private:
48 |
49 | static std::string append(std::string fieldName, Json::Value &properties, std::string appendToken, std::string idFieldName = "");
50 |
51 | static std::string append(std::string fieldName, std::string propertiesNamePrefix, Json::Value &properties, std::string appendToken, std::string idFieldName = "");
52 | };
53 | }
54 |
55 | #endif /* kit_hpp */
56 |
--------------------------------------------------------------------------------