├── .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 | --------------------------------------------------------------------------------