├── .Rbuildignore ├── .github ├── .gitignore └── workflows │ └── check-standard.yaml ├── .gitignore ├── .travis.yml ├── DESCRIPTION ├── LICENSE ├── NAMESPACE ├── NEWS.md ├── R ├── neo4j_import.R ├── neo4j_query.R ├── neo4j_restart.R ├── neo4j_rmdir.R ├── neo4j_rmfiles.R ├── neo4j_start.R ├── neo4j_status.R ├── neo4j_stop.R └── neo4j_wipe.R ├── README.Rmd ├── README.md ├── man ├── neo4j_import.Rd ├── neo4j_query.Rd ├── neo4j_restart.Rd ├── neo4j_rmdir.Rd ├── neo4j_rmfiles.Rd ├── neo4j_start.Rd ├── neo4j_status.Rd ├── neo4j_stop.Rd └── neo4j_wipe.Rd ├── neo4jshell.Rproj ├── neo4jshell.png └── vignettes ├── .gitignore ├── admin.Rmd ├── files.Rmd └── querying.Rmd /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^\.travis\.yml$ 4 | ^\.github$ 5 | ^CRAN-RELEASE$ 6 | ^codecov\.yml$ 7 | ^cran-comments\.md$ 8 | ^README\.Rmd$ 9 | neo4jshell.png 10 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/workflows/check-standard.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/master/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: R-CMD-check 10 | 11 | jobs: 12 | R-CMD-check: 13 | runs-on: ${{ matrix.config.os }} 14 | 15 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 16 | 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | config: 21 | - {os: macOS-latest, r: 'release'} 22 | - {os: windows-latest, r: 'release'} 23 | - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} 24 | - {os: ubuntu-latest, r: 'release'} 25 | - {os: ubuntu-latest, r: 'oldrel-1'} 26 | 27 | env: 28 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 29 | R_KEEP_PKG_SOURCE: yes 30 | 31 | steps: 32 | - uses: actions/checkout@v2 33 | 34 | - name: Install libssh-dev 35 | if: runner.os == 'Linux' 36 | run: sudo apt-get install -y libssh-dev 37 | 38 | - uses: r-lib/actions/setup-pandoc@v2 39 | 40 | - uses: r-lib/actions/setup-r@v1 41 | with: 42 | r-version: ${{ matrix.config.r }} 43 | http-user-agent: ${{ matrix.config.http-user-agent }} 44 | use-public-rspm: true 45 | 46 | - uses: r-lib/actions/setup-r-dependencies@v1 47 | with: 48 | extra-packages: rcmdcheck 49 | 50 | - uses: r-lib/actions/setup-tinytex@v2 51 | - uses: r-lib/actions/check-r-package@v1 52 | 53 | - name: Show testthat output 54 | if: always() 55 | run: find check -name 'testthat.Rout*' -exec cat '{}' \; || true 56 | shell: bash 57 | 58 | - name: Upload check results 59 | if: failure() 60 | uses: actions/upload-artifact@main 61 | with: 62 | name: ${{ runner.os }}-r${{ matrix.config.r }}-results 63 | path: check 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | inst/doc 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # R for travis: see documentation at https://docs.travis-ci.com/user/languages/r 2 | 3 | language: R 4 | cache: packages 5 | 6 | before_install: 7 | - sudo apt-get -y install libssh-dev 8 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: neo4jshell 2 | Type: Package 3 | Title: Querying and Managing 'Neo4J' Databases in 'R' 4 | Version: 0.1.2.9000 5 | Authors@R: 6 | c(person(given = "Keith", 7 | family = "McNulty", 8 | role = c("cre", "aut", "cph"), 9 | email = "keith.mcnulty@gmail.com", 10 | comment = c(ORCID = "0000-0002-2332-1654")), 11 | person(given = "Liz", 12 | family = "Romero", 13 | role = c("ctb"), 14 | email = "liz.romero357@gmail.com")) 15 | Description: Sends queries to a specified 'Neo4J' graph database, capturing results in a dataframe where appropriate. 16 | Other useful functions for the importing and management of data on the 'Neo4J' server and basic local server admin. 17 | License: MIT + file LICENSE 18 | Encoding: UTF-8 19 | LazyData: true 20 | Imports: 21 | magrittr, 22 | ssh, 23 | sys, 24 | fs, 25 | R.utils 26 | RoxygenNote: 7.1.1 27 | Suggests: 28 | knitr, 29 | rmarkdown 30 | SystemRequirements: 31 | neo4j - http://www.neo4j.com, 32 | cypher-shell - https://github.com/neo4j/cypher-shell/releases 33 | VignetteBuilder: knitr 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2019 2 | COPYRIGHT HOLDER: Keith McNulty 3 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | exportPattern("^[[:alpha:]]+") 2 | importFrom("utils", "read.csv", "write.csv", "untar", "unzip") 3 | importFrom("magrittr", "%>%") 4 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # neo4jshell 0.1.1 2 | 3 | * Added a `NEWS.md` file to track changes to the package. 4 | * Addressed problematic data type guessing in neo4j_query by pulling all data as character (#10). 5 | 6 | # neo4jshell 0.1.2 7 | 8 | * Fixed a bug that returned unexpected output shape for single row results from `neo4j_query()`. 9 | 10 | # neo4jshell 0.1.2.9000 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /R/neo4j_import.R: -------------------------------------------------------------------------------- 1 | #' Imports a csv or a compressed file to Neo4J import folder. 2 | #' 3 | #' @param local Logical indicating whether import is to a locally hosted or a remotely hosted server. 4 | #' @param con If remotely hosted server, list containing three objects: address, uid, pwd as character strings providing connection to the Neo4J server. 5 | #' uid and pwd must be for an account on the server with appropriate permissions. 6 | #' @param source Character string of local path to the csv, zip or tar.gz compressed csv file to be imported 7 | #' @param import_dir Character string of full path to the Neo4J import directory 8 | #' @param gunzip_path Path to gunzip on the local or remote server to be passed to the system command following import if necessary. 9 | #' @param tar_path Path to tar on the local or remote server to be passed to the system command following import if necessary. 10 | #' @param unzip_path Path to unzip on the local or remote server to be passed to the system command if necessary. 11 | #' 12 | #' @return System messages confirming success or error. zip or tar files will be removed after import and decompression. 13 | #' 14 | #' @examples 15 | #' # import zip to local import directory, with zip in the local system PATH variable 16 | #' write.csv(mtcars, "mtcars.csv") 17 | #' zip("mtcars.zip", "mtcars.csv") 18 | #' fs::dir_create("import") 19 | #' neo4j_import(local = TRUE, source = "mtcars.zip") 20 | #' fs::file_delete("mtcars.zip") 21 | #' fs::file_delete("mtcars.csv") 22 | #' fs::dir_delete("import") 23 | 24 | 25 | 26 | neo4j_import <- function (local = FALSE, con = list(address = NULL, uid = NULL, pwd = NULL), source = NULL, 27 | import_dir = "import", unzip_path = "unzip", 28 | gunzip_path = "gunzip", tar_path = "tar") { 29 | 30 | 31 | if (substr(import_dir, nchar(import_dir), nchar(import_dir)) != "/") { 32 | import_dir <- paste0(import_dir, "/") 33 | } 34 | 35 | tmp1 <- tempfile() 36 | tmp2 <- tempfile() 37 | tmp3 <- tempfile() 38 | tmp4 <- tempfile() 39 | 40 | if (local == FALSE) { 41 | 42 | base_address <- basename(con$address) 43 | if (grepl(":", base_address)) { 44 | base_address <- gsub(":(.*)", "", base_address) 45 | } 46 | 47 | ssh_uid <- paste0(con$uid, "@", base_address) 48 | 49 | if (substr(source, nchar(source) - 3, nchar(source)) == ".csv") { 50 | session <- ssh::ssh_connect(ssh_uid, passwd = con$pwd) 51 | ssh::scp_upload(session, source, to = import_dir) 52 | ssh::ssh_disconnect(session) 53 | message("Import successful!") 54 | } else if (substr(source, nchar(source) - 3, nchar(source)) == ".zip") { 55 | session <- ssh::ssh_connect(ssh_uid, passwd = con$pwd) 56 | ssh::scp_upload(session, source, to = import_dir) 57 | output1 <- ssh::ssh_exec_wait(session, paste(unzip_path, "-o", paste0(import_dir, basename(source)), "-d", import_dir), std_err = tmp1) 58 | output2 <- ssh::ssh_exec_wait(session, paste("rm", paste0(import_dir, basename(source))), std_err = tmp2) 59 | ssh::ssh_disconnect(session) 60 | if (output1 == 0 & output2 == 0) { 61 | message("Import and unzip successful! Zip file has been removed!") 62 | } else { 63 | c(readLines(tmp1), readLines(tmp2)) %>% paste(collapse = " ") %>% noquote() %>% stop(call. = FALSE) 64 | } 65 | } else if (substr(source, nchar(source) - 6, nchar(source)) == ".tar.gz") { 66 | session <- ssh::ssh_connect(ssh_uid, passwd = con$pwd) 67 | ssh::scp_upload(session, source, to = import_dir) 68 | output1 <- ssh::ssh_exec_wait(session, paste(gunzip_path, "-f", paste0(import_dir, basename(source))), std_err = tmp1) 69 | output2 <- ssh::ssh_exec_wait(session, paste(tar_path, "-C", import_dir, "-xvf", paste0(import_dir, gsub(".gz", "", basename(source)))), std_err = tmp2) 70 | output3 <- ssh::ssh_exec_wait(session, paste("rm", paste0(import_dir, gsub(".gz", "", basename(source)))), std_err = tmp3) 71 | ssh::ssh_disconnect(session) 72 | if (output1 == 0 & output2 == 0 & output3 == 0) { 73 | message("Import and gunzip successful! Tar file has been removed!") 74 | } else { 75 | c(readLines(tmp1), readLines(tmp2), readLines(tmp3)) %>% paste(collapse = " ") %>% noquote() %>% stop(call. = FALSE) 76 | } 77 | } else { 78 | stop("Source is not a .csv, .zip or a .tar.gz file.") 79 | } 80 | 81 | } else { 82 | 83 | if (substr(source, nchar(source) - 3, nchar(source)) == ".csv") { 84 | new <- paste0(import_dir, basename(source)) 85 | fs::file_copy(source, new, overwrite = TRUE) 86 | message("Import successful!") 87 | } else if (substr(source, nchar(source) - 3, nchar(source)) == ".zip") { 88 | new <- paste0(import_dir, basename(source)) 89 | fs::file_copy(source, new, overwrite = TRUE) 90 | unzip(new, exdir = import_dir, unzip = unzip_path) 91 | fs::file_delete(new) 92 | message("Import and unzip successful! Zip file has been removed!") 93 | } else if (substr(source, nchar(source) - 6, nchar(source)) == ".tar.gz") { 94 | new <- paste0(import_dir, basename(source)) 95 | fs::file_copy(source, new, overwrite = TRUE) 96 | R.utils::gunzip(new) 97 | untar(gsub(".gz", "", new), exdir = import_dir, tar = tar_path) 98 | fs::file_delete(gsub(".gz", "", new)) 99 | message("Import and gunzip successful! Tar file has been removed!") 100 | } else { 101 | stop("Source is not a .csv, .zip or a .tar.gz file.") 102 | } 103 | 104 | } 105 | } 106 | 107 | -------------------------------------------------------------------------------- /R/neo4j_query.R: -------------------------------------------------------------------------------- 1 | #' Execute a query string in Neo4J using cypher-shell and capture output 2 | #' 3 | #' @param con List containing three objects: bolt address, uid, pwd as character strings providing connection to the Neo4J server 4 | #' @param qry Character string of the query or queries to be sent to Neo4J. Read queries should be single queries. 5 | #' @param shell_path If cypher-shell is not in the PATH system variable, the full local path to cypher-shell executable. 6 | #' @param database The name of the database if other than the default database. (For multi-tenancy installations). 7 | #' @param encryption Passes encryption argument to cypher-shell if necessary. Older versions of cypher-shell may require 'true' or 'false' to be passed. 8 | #' 9 | #' @return A dataframe of results if the read query is successful. A text string if an error is encountered. 10 | #' Write queries will return a zero length response if successful. 11 | #' If multiple read queries were submitted, only the results of the final query will be returned. 12 | #' 13 | #' @examples 14 | #' # if neo4j exists, start the local server, give it a moment to fire up, and run a query 15 | #' if (nzchar(Sys.which("neo4j"))) { 16 | #' neo4j_start() 17 | #' Sys.sleep(2) 18 | #' graph <- list(address = "bolt://localhost:7687", uid = "neo4j", pwd = "password") 19 | #' neo4j_query(con = graph, qry = "MATCH (n) RETURN (n)") 20 | #' } 21 | 22 | 23 | 24 | neo4j_query <- function(con = list(address = NULL, uid = NULL, pwd = NULL), qry = NULL, 25 | shell_path = "cypher-shell", database = NULL, encryption = c("default", "true", "false")) { 26 | 27 | encryption <- match.arg(encryption) 28 | 29 | qry <- gsub("\n", " ", qry) 30 | qry <- gsub("\t", "", qry) 31 | qry <- gsub("^\\s+|\\s+$", "", qry) 32 | 33 | # remove trailing ; 34 | 35 | if (substr(qry, nchar(qry), nchar(qry)) == ";") { 36 | qry <- substr(qry, 1, nchar(qry) - 1) 37 | } 38 | 39 | # split multiple queries into single queries inside a vector (command line cypher-shell only accepts one query at a time) 40 | 41 | if (grepl(";", qry)) { 42 | qry <- strsplit(qry, ";") 43 | qry <- as.vector(qry[[1]]) 44 | } else { 45 | qry <- as.vector(qry) 46 | } 47 | 48 | # execute queries 49 | 50 | for (i in 1:length(qry)) { 51 | if (!is.null(database)) { 52 | assign(paste0("args_", i), 53 | c("-a", con$address, 54 | "-u", con$uid, 55 | "-p", con$pwd, 56 | "-d", database, 57 | "--encryption", encryption, 58 | qry[i]) %>% 59 | noquote() 60 | ) 61 | } else { 62 | assign(paste0("args_", i), 63 | c("-a", con$address, 64 | "-u", con$uid, 65 | "-p", con$pwd, 66 | "--encryption", encryption, 67 | qry[i]) %>% 68 | noquote() 69 | ) 70 | } 71 | 72 | assign(paste0("tmp1_", i), tempfile()) 73 | assign(paste0("tmp2_", i), tempfile()) 74 | } 75 | 76 | for (i in 1:length(qry)) { 77 | assign(paste0("output_", i), 78 | sys::exec_wait(shell_path, 79 | args = get(paste0("args_", i)), 80 | std_out = get(paste0("tmp1_", i)), 81 | std_err = get(paste0("tmp2_", i)) 82 | ) 83 | ) 84 | } 85 | 86 | # gather output statuses in vector 87 | 88 | if (length(qry) == 1) { 89 | output <- get(paste0("output_", 1)) 90 | } else { 91 | output <- get(paste0("output_", 1)) 92 | for (k in 2:length(qry)) { 93 | output <- c(output, get(paste0("output_", i))) 94 | } 95 | } 96 | 97 | 98 | 99 | tmp_final <- tempfile() 100 | 101 | # if all queries successful, write results of final query or confirm zero-length response 102 | if (sum(output) == 0) { 103 | tmp <- readLines(get(paste0("tmp1_", length(qry)))) 104 | if (length(tmp) > 0) { 105 | tmp <- gsub("(?:\\G(?!^)|\\[)[^][,]*\\K,(?=[^][]*])", ";;;", tmp, perl = TRUE) # deal with embedded [] lists for read.csv 106 | tmp <- gsub("(?:\\G(?!^)|\\{)[^{},]*\\K,(?=[^{}]*})", ";;;", tmp, perl = TRUE) # deal with embedded {} lists for read.csv 107 | write(tmp, tmp_final) 108 | r <- read.csv(tmp_final, colClasses = "character", strip.white = TRUE) 109 | r <- lapply(r, function (x) gsub(";;;", ",", x)) 110 | as.data.frame(r, stringsAsFactors = FALSE) 111 | } else { 112 | message("Query succeeded with a zero length response from Neo4J") 113 | } 114 | } else { 115 | # if any error occurred, show all responses from Neo4J 116 | if (length(qry) == 1) { 117 | readLines(get("tmp2_1")) %>% paste(collapse = " ") %>% noquote() %>% stop(call. = FALSE) 118 | } else { 119 | tmpvec <- readLines(get("tmp2_1")) 120 | for (w in 2:length(qry)) { 121 | tmpvec <- c(tmpvec, readLines(get(paste0("tmp2_", w)))) 122 | } 123 | tmpvec %>% paste(collapse = " ") %>% noquote() %>% stop(call. = FALSE) 124 | } 125 | 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /R/neo4j_restart.R: -------------------------------------------------------------------------------- 1 | #' Restart a local Neo4J database 2 | #' 3 | #' @param neo4j_path Path to the Neo4J executable (usually in the bin directory of the Neo4J installation) 4 | #' 5 | #' @return System messages 6 | #' 7 | #' @examples 8 | #' # if neo4j exists, restart local graph with neo4j executable in the system PATH variable 9 | #' if (nzchar(Sys.which("neo4j"))) { 10 | #' neo4j_restart() 11 | #' } 12 | 13 | 14 | neo4j_restart <- function(neo4j_path = "neo4j") { 15 | sys::exec_wait(neo4j_path, "restart") 16 | } 17 | -------------------------------------------------------------------------------- /R/neo4j_rmdir.R: -------------------------------------------------------------------------------- 1 | #' Remove subdirectory and all its contents from the Neo4J import directory 2 | #' 3 | #' @param local Logical indicating whether import is to a locally hosted or remotely hosted server. 4 | #' @param con If remotely hosted server, list containing three objects: address, uid, pwd as character strings providing connection to the Neo4J server. 5 | #' uid and pwd must be for an account on the server with appropriate permissions. 6 | #' @param dir Character string of the Neo4J import subdirectory name to be deleted. 7 | #' @param import_dir Character string of path to the Neo4J import directory. 8 | #' 9 | #' @return A success message if successful. A error message otherwise. 10 | #' 11 | #' @examples 12 | #' # remove a subdirectory and all its contents from the local import directory 13 | #' fs::dir_create("import/data") 14 | #' fs::file_create("import/data/data.csv") 15 | #' neo4j_rmdir(local = TRUE, dir = "data", import_dir = "import") 16 | #' fs::dir_delete("import") 17 | 18 | 19 | 20 | neo4j_rmdir <- function (local = FALSE, con = list(address = NULL, uid = NULL, pwd = NULL), dir = NULL, import_dir = "import") { 21 | 22 | if (substr(import_dir, nchar(import_dir), nchar(import_dir)) != "/") { 23 | import_dir <- paste0(import_dir, "/") 24 | } 25 | 26 | filestring <- paste0(import_dir, dir) 27 | tmp1 <- tempfile() 28 | 29 | if (local == FALSE) { 30 | 31 | base_address <- basename(con$address) 32 | if (grepl(":", base_address)) { 33 | base_address <- gsub(":(.*)", "", base_address) 34 | } 35 | 36 | ssh_uid <- paste0(con$uid, "@", base_address) 37 | session <- ssh::ssh_connect(ssh_uid, passwd = con$pwd) 38 | output <- ssh::ssh_exec_wait(session, command = paste("rm -r", filestring), std_err = tmp1) 39 | ssh::ssh_disconnect(session) 40 | 41 | if (output == 0) { 42 | message("Directory and all contents removed successfully!") 43 | } else { 44 | readLines(tmp1) %>% paste(collapse = " ") %>% noquote() %>% stop(call. = FALSE) 45 | } 46 | 47 | } else { 48 | 49 | fs::dir_delete(filestring) 50 | message("Directory and all contents removed successfully!") 51 | 52 | } 53 | 54 | 55 | 56 | } 57 | 58 | -------------------------------------------------------------------------------- /R/neo4j_rmfiles.R: -------------------------------------------------------------------------------- 1 | #' Remove files from the Neo4J import directory 2 | #' 3 | #' @param local Logical indicating whether import is to a locally hosted or remotely hosted server. 4 | #' @param con If remotely hosted server, list containing three objects: address, uid, pwd as character strings providing connection to the Neo4J server. 5 | #' uid and pwd must be for an account on the server with appropriate permissions. 6 | #' @param files Character vector of file names to be removed. 7 | #' @param import_dir Character string of path to the Neo4J import directory. 8 | #' 9 | #' @return A success message if successful. An error message otherwise. 10 | #' 11 | #' @examples 12 | #' # remove file from local import directory 13 | #' fs::dir_create("import") 14 | #' fs::file_create("import/data.csv") 15 | #' neo4j_rmfiles(local = TRUE, files = "data.csv", import_dir = "import") 16 | #' fs::dir_delete("import") 17 | 18 | 19 | 20 | neo4j_rmfiles <- function (local = FALSE, con = list(address = NULL, uid = NULL, pwd = NULL), files = NULL, import_dir = "import") { 21 | 22 | if (substr(import_dir, nchar(import_dir), nchar(import_dir)) != "/") { 23 | import_dir <- paste0(import_dir, "/") 24 | } 25 | 26 | files <- paste0(import_dir, files) 27 | filestring <- paste(files, collapse = " ") 28 | tmp1 <- tempfile() 29 | 30 | if (local == FALSE) { 31 | 32 | base_address <- basename(con$address) 33 | if (grepl(":", base_address)) { 34 | base_address <- gsub(":(.*)", "", base_address) 35 | } 36 | 37 | ssh_uid <- paste0(con$uid, "@", base_address) 38 | session <- ssh::ssh_connect(ssh_uid, passwd = con$pwd) 39 | output <- ssh::ssh_exec_wait(session, command = paste("rm", filestring), std_err = tmp1) 40 | ssh::ssh_disconnect(session) 41 | 42 | if (output == 0) { 43 | message("Files removed successfully!") 44 | } else { 45 | readLines(tmp1) %>% paste(collapse = " ") %>% noquote() %>% stop(call. = FALSE) 46 | } 47 | 48 | } else { 49 | 50 | fs::file_delete(files) 51 | message("Files removed successfully!") 52 | 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /R/neo4j_start.R: -------------------------------------------------------------------------------- 1 | #' Start a local Neo4J database 2 | #' 3 | #' @param neo4j_path Path to the Neo4J executable (usually in the bin directory of the Neo4J installation) 4 | #' 5 | #' @return System messages 6 | #' 7 | #' @examples 8 | #' # if neo4j exists, start local graph on with neo4j executable in the system PATH variable 9 | #' if (nzchar(Sys.which("neo4j"))) { 10 | #' neo4j_start() 11 | #' } 12 | 13 | 14 | 15 | neo4j_start <- function(neo4j_path = "neo4j") { 16 | sys::exec_wait(neo4j_path, "start") 17 | } 18 | -------------------------------------------------------------------------------- /R/neo4j_status.R: -------------------------------------------------------------------------------- 1 | #' Check status of a local Neo4J database 2 | #' 3 | #' @param neo4j_path Path to the Neo4J executable (usually in the bin directory of the Neo4J installation) 4 | #' 5 | #' @return System messages 6 | #' 7 | #' @examples 8 | #' # if neo4j exists, check status local graph with neo4j executable in the system PATH variable 9 | #' if (nzchar(Sys.which("neo4j"))) { 10 | #' neo4j_status() 11 | #' } 12 | 13 | 14 | neo4j_status <- function(neo4j_path = "neo4j") { 15 | sys::exec_wait(neo4j_path, "status") 16 | } 17 | -------------------------------------------------------------------------------- /R/neo4j_stop.R: -------------------------------------------------------------------------------- 1 | #' Stop a local Neo4J database 2 | #' 3 | #' @param neo4j_path Path to the Neo4J executable (usually in the bin directory of the Neo4J installation) 4 | #' 5 | #' @return System messages 6 | #' 7 | #' @examples 8 | #' # if neo4j exists, stop local graph with neo4j executable in the system PATH variable 9 | #' if (nzchar(Sys.which("neo4j"))) { 10 | #' neo4j_stop() 11 | #' } 12 | 13 | 14 | neo4j_stop <- function(neo4j_path = "neo4j") { 15 | sys::exec_wait(neo4j_path, "stop") 16 | } 17 | -------------------------------------------------------------------------------- /R/neo4j_wipe.R: -------------------------------------------------------------------------------- 1 | #' Wipe a complete local graph database in Neo4J 2 | #' 3 | #' @param database Name of local graph database directory to wipe. 4 | #' @param data_path Path to the local Neo4J data directory 5 | #' 6 | #' @return Success or error message 7 | #' 8 | #' @examples 9 | #' # wipe database directory 10 | #' fs::dir_create("data/databases/foo") 11 | #' neo4j_wipe(database = "foo", data_path = "data") 12 | #' fs::dir_delete("data") 13 | 14 | neo4j_wipe <- function(database = NULL, data_path = NULL) { 15 | if (substr(data_path, nchar(data_path), nchar(data_path)) != "/") { 16 | data_path <- paste0(data_path, "/") 17 | } 18 | 19 | fs::dir_delete(paste0(data_path, "databases/", database)) 20 | message("Graph wiped successfully!") 21 | } 22 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r, include = FALSE} 8 | knitr::opts_chunk$set( 9 | collapse = TRUE, 10 | comment = "#>", 11 | fig.path = "man/figures/README-", 12 | out.width = "100%" 13 | ) 14 | 15 | ``` 16 | 17 | # neo4jshell 18 | 19 | 20 | [![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://www.tidyverse.org/lifecycle/#experimental) 21 | [![CRAN status](https://www.r-pkg.org/badges/version/neo4jshell)](https://CRAN.R-project.org/package=neo4jshell) 22 | [![Total Downloads](http://cranlogs.r-pkg.org/badges/grand-total/neo4jshell?color=green)](https://cran.r-project.org/package=neo4jshell) 23 | [![R build status](https://github.com/keithmcnulty/neo4jshell/workflows/R-CMD-check/badge.svg)](https://github.com/keithmcnulty/neo4jshell/actions) 24 | [![Travis build status](https://travis-ci.com/keithmcnulty/neo4jshell.svg?branch=master)](https://travis-ci.com/keithmcnulty/neo4jshell) 25 | 26 | 27 | The goal of neo4jshell is to provide rapid querying of 'Neo4J' graph databases by offering a programmatic interface with 'cypher-shell'. A wide variety of other functions are offered that allow importing and management of data files for local and remote servers, as well as simple administration of local servers for development purposes. 28 | 29 | ## Pre-installation notes 30 | This package requires the `ssh` package for interacting with remote 'Neo4J' databases, which requires `libssh` to be installed. See the vignettes for the `ssh` package [here](https://CRAN.R-project.org/package=ssh) for more details. 31 | 32 | This package also requires the 'cypher-shell' executable to be available **locally**. This is installed as standard in 'Neo4J' installations and can usually be found in the `bin` directory of that installation. It can also be installed standalone using Homebrew or is available here: https://github.com/neo4j/cypher-shell. 33 | 34 | It is recommended, for ease of use, that the path to the 'cypher-shell' executable is added to your `PATH` environment variable. If not, you should record its location for use in some of the functions within this package. 35 | 36 | 37 | ## Installation 38 | 39 | You can install the released version of neo4jshell from [CRAN](https://CRAN.R-project.org) with: 40 | 41 | ``` r 42 | install.packages("neo4jshell") 43 | ``` 44 | 45 | And the development version from [GitHub](https://github.com/) with: 46 | 47 | ``` r 48 | # install.packages("devtools") 49 | devtools::install_github("keithmcnulty/neo4jshell") 50 | ``` 51 | 52 | ## Functionality 53 | 54 | ### Query 55 | 56 | `neo4j_query()` sends queries to the specified 'Neo4J' graph database and, where appropriate, retrieves the results in a dataframe. 57 | 58 | In this example, the movies dataset has been started locally in the 'Neo4J' browser, with a user created that has the credentials indicated. `cypher-shell` is in the local system path. 59 | 60 | ``` {r, message = FALSE, warning = FALSE} 61 | library(neo4jshell) 62 | library(dplyr) 63 | library(tibble) 64 | ``` 65 | ```{r} 66 | # set credentials (no port required in bolt address) 67 | neo_movies <- list(address = "bolt://localhost", uid = "neo4j", pwd = "password") 68 | 69 | # find directors of movies with Kevin Bacon as actor 70 | CQL <- 'MATCH (p1:Person {name: "Kevin Bacon"})-[:ACTED_IN]->(m:Movie)<-[:DIRECTED]-(p2:Person) 71 | RETURN p2.name, m.title;' 72 | 73 | # run query 74 | neo4j_query(con = neo_movies, qry = CQL) 75 | 76 | ``` 77 | 78 | Older versions of 'Neo4J' and 'cypher-shell' (<4.0) will require the `encryption` argument to be explicitly `'true'` or `'false'`. For newer versions, which have multi-tenancy, you can use the `database` argument to specify the database to query. 79 | 80 | ### Server management 81 | 82 | - `neo4j_import()` imports a csv, zip or tar.gz file from a local source into the specified 'Neo4J' import directory, uncompresses compressed files and removes the original compressed file as clean up. 83 | - `neo4j_rmfiles()` removes specified files from specified 'Neo4J' import directory 84 | - `neo4j_rmdir()` removes entire specified subdirectories from specified 'Neo4J' import directory 85 | 86 | ### Remote development 87 | 88 | In this general example, we can see how these functions can be used for smooth ETL to a remote 'Neo4J' server. This example assumes that the URL of the server that hosts the 'Neo4J' database is the same as the bolt URL for the 'Neo4J' database. If not, a different set of credentials will be needed for using `neo4j_import()`. 89 | 90 | ``` 91 | # credentials (note no port required in server address) 92 | neo_server <- list(address = "bolt://neo.server.address", uid = "neo4j", pwd = "password") 93 | 94 | # csv data file to be loaded onto 'Neo4J' server (path relative to current working directory) 95 | datafile <- "data.csv" 96 | 97 | # CQL query to write data from datafile to 'Neo4J' 98 | loadcsv_CQL <- "LOAD CSV FROM 'file:///data.csv' etc etc;" 99 | 100 | # path to import directory on remote 'Neo4J' server (should be relative to user home directory on remote server) 101 | impdir <- "./import" 102 | 103 | # import data 104 | neo4jshell::neo4j_import(con = neo_server, source = datafile, import_dir = impdir) 105 | 106 | # write data to 'Neo4J' (assumes cypher-shell is in system PATH variable) 107 | neo4jshell:neo4j_query(con = neo_server, qry = loadcsv_CQL) 108 | 109 | # remove data file as clean-up 110 | neo4jshell::neo4j_rmfiles(con = neo_server, files = datafile, import_dir = impdir) 111 | 112 | ``` 113 | In Windows, the 'cypher-shell' executable may need to be specified with the file extension, for example `shell_path = "cypher-shell.bat"`. 114 | 115 | ### Local Development 116 | 117 | If you are working with the 'Neo4J' server locally, below will help you get started. 118 | 119 | First, the code below is relative to user and is using 'Neo4J 4.0.4 Community' installed at my user's root. The directory containing the 'cypher-shell' and 'neo4j' executables are in my system's PATH environment variables. 120 | 121 | ``` {r} 122 | ## start the local server 123 | neo4j_start() 124 | 125 | ## setup connection credentials and import directory location 126 | neo_con <- list(address = "bolt://localhost:7687", uid = "neo4j", pwd = "password") 127 | import_loc <- path.expand("~/neo4j-community-4.0.4/import/") 128 | ``` 129 | 130 | First we save `mtcars` to a `.csv` file, and we compress that file. This package supports a number of delivery formats, but we use a `.zip` file as an example. 131 | 132 | ```{r} 133 | mtcars <- mtcars %>% 134 | tibble::rownames_to_column(var = "model") 135 | 136 | write.csv(mtcars, "mtcars.csv", row.names = FALSE) 137 | zip("mtcars.zip", "mtcars.csv") 138 | ``` 139 | 140 | Now we use `neo4j_import()` to place a **copy** of this file within the import directory you defined in `import_loc` above. 141 | 142 | ```{r} 143 | neo4j_import(local = TRUE, graph, source = "mtcars.zip", import_dir = import_loc) 144 | ``` 145 | 146 | We now write a CQL query to write some information from `mtcars.csv` to the graph, and execute that query. 147 | 148 | ```{r} 149 | CQL <- "LOAD CSV WITH HEADERS FROM 'file:///mtcars.csv' AS row 150 | WITH row WHERE row.model IS NOT NULL 151 | MERGE (c:Car {name: row.model});" 152 | 153 | neo4j_query(neo_con, CQL) 154 | 155 | ``` 156 | 157 | 158 | Now, let's remove the `mtcars.csv` file from the import directory of our local server as cleanup. If you want to use a sub-directory to help manage your files during an ETL into 'Neo4J', you can remove that local sub-directory when your process has completed using `neo4j_rmdir()`. 159 | 160 | ```{r} 161 | ## remove the file 162 | neo4j_rmfiles(local = TRUE, graph, files="mtcars.csv", import_dir = import_loc) 163 | ``` 164 | 165 | Now let's run a query to check the data was loaded to the graph. 166 | 167 | ```{r} 168 | CQL <- "MATCH (c:Car) RETURN c.name as name LIMIT 5;" 169 | 170 | neo4j_query(neo_con, CQL) 171 | 172 | ``` 173 | 174 | 175 | 176 | ### Local server administration and control 177 | 178 | - `neo4j_start()` starts a local 'Neo4J' instance 179 | - `neo4j_stop()` stops a local 'Neo4J' instance 180 | - `neo4j_restart()` restarts a local 'Neo4J' instance 181 | - `neo4j_status()` returns the status of a local 'Neo4J' instance 182 | - `neo4j_wipe()` wipes an entire graph from a local 'Neo4J' instance 183 | 184 | 185 | For example: 186 | 187 | ```{r} 188 | 189 | # my server was already running, confirm 190 | neo4j_status() 191 | 192 | # stop the server 193 | neo4j_stop() 194 | 195 | # restart 196 | neo4j_start() 197 | 198 | # give it a few seconds to fire up 199 | Sys.sleep(10) 200 | 201 | # query again 202 | neo4j_query(neo_con, qry="MATCH (c:Car) RETURN c.name as name LIMIT 5;") 203 | ``` 204 | 205 | If you are using an admin account and you are using 'Neo4J 4+' you can check what databases are available by querying the system database. 206 | 207 | ```{r} 208 | neo4j_query(neo_con, qry="SHOW DATABASES;", database = "system") 209 | ``` 210 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # neo4jshell 5 | 6 | 7 | 8 | [![Lifecycle: 9 | experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental) 10 | [![CRAN 11 | status](https://www.r-pkg.org/badges/version/neo4jshell)](https://CRAN.R-project.org/package=neo4jshell) 12 | [![Total 13 | Downloads](http://cranlogs.r-pkg.org/badges/grand-total/neo4jshell?color=green)](https://cran.r-project.org/package=neo4jshell) 14 | [![R build 15 | status](https://github.com/keithmcnulty/neo4jshell/workflows/R-CMD-check/badge.svg)](https://github.com/keithmcnulty/neo4jshell/actions) 16 | [![Travis build 17 | status](https://app.travis-ci.com/keithmcnulty/neo4jshell.svg?branch=master)](https://app.travis-ci.com/keithmcnulty/neo4jshell) 18 | 19 | 20 | The goal of neo4jshell is to provide rapid querying of ‘Neo4J’ graph 21 | databases by offering a programmatic interface with ‘cypher-shell’. A 22 | wide variety of other functions are offered that allow importing and 23 | management of data files for local and remote servers, as well as simple 24 | administration of local servers for development purposes. 25 | 26 | ## Pre-installation notes 27 | 28 | This package requires the `ssh` package for interacting with remote 29 | ‘Neo4J’ databases, which requires `libssh` to be installed. See the 30 | vignettes for the `ssh` package 31 | [here](https://CRAN.R-project.org/package=ssh) for more details. 32 | 33 | This package also requires the ‘cypher-shell’ executable to be available 34 | **locally**. This is installed as standard in ‘Neo4J’ installations and 35 | can usually be found in the `bin` directory of that installation. It can 36 | also be installed standalone using Homebrew or is available here: 37 | . 38 | 39 | It is recommended, for ease of use, that the path to the ‘cypher-shell’ 40 | executable is added to your `PATH` environment variable. If not, you 41 | should record its location for use in some of the functions within this 42 | package. 43 | 44 | ## Installation 45 | 46 | You can install the released version of neo4jshell from 47 | [CRAN](https://CRAN.R-project.org) with: 48 | 49 | ``` r 50 | install.packages("neo4jshell") 51 | ``` 52 | 53 | And the development version from [GitHub](https://github.com/) with: 54 | 55 | ``` r 56 | # install.packages("devtools") 57 | devtools::install_github("keithmcnulty/neo4jshell") 58 | ``` 59 | 60 | ## Functionality 61 | 62 | ### Query 63 | 64 | `neo4j_query()` sends queries to the specified ‘Neo4J’ graph database 65 | and, where appropriate, retrieves the results in a dataframe. 66 | 67 | In this example, the movies dataset has been started locally in the 68 | ‘Neo4J’ browser, with a user created that has the credentials 69 | indicated. `cypher-shell` is in the local system path. 70 | 71 | ``` r 72 | library(neo4jshell) 73 | library(dplyr) 74 | library(tibble) 75 | ``` 76 | 77 | ``` r 78 | # set credentials (no port required in bolt address) 79 | neo_movies <- list(address = "bolt://localhost", uid = "neo4j", pwd = "password") 80 | 81 | # find directors of movies with Kevin Bacon as actor 82 | CQL <- 'MATCH (p1:Person {name: "Kevin Bacon"})-[:ACTED_IN]->(m:Movie)<-[:DIRECTED]-(p2:Person) 83 | RETURN p2.name, m.title;' 84 | 85 | # run query 86 | neo4j_query(con = neo_movies, qry = CQL) 87 | #> p2.name m.title 88 | #> 1 Ron Howard Frost/Nixon 89 | #> 2 Rob Reiner A Few Good Men 90 | #> 3 Ron Howard Apollo 13 91 | ``` 92 | 93 | Older versions of ‘Neo4J’ and ‘cypher-shell’ (\<4.0) will require the 94 | `encryption` argument to be explicitly `'true'` or `'false'`. For newer 95 | versions, which have multi-tenancy, you can use the `database` argument 96 | to specify the database to query. 97 | 98 | ### Server management 99 | 100 | - `neo4j_import()` imports a csv, zip or tar.gz file from a local 101 | source into the specified ‘Neo4J’ import directory, uncompresses 102 | compressed files and removes the original compressed file as clean 103 | up. 104 | - `neo4j_rmfiles()` removes specified files from specified ‘Neo4J’ 105 | import directory 106 | - `neo4j_rmdir()` removes entire specified subdirectories from 107 | specified ‘Neo4J’ import directory 108 | 109 | ### Remote development 110 | 111 | In this general example, we can see how these functions can be used for 112 | smooth ETL to a remote ‘Neo4J’ server. This example assumes that the URL 113 | of the server that hosts the ‘Neo4J’ database is the same as the bolt 114 | URL for the ‘Neo4J’ database. If not, a different set of credentials 115 | will be needed for using `neo4j_import()`. 116 | 117 | # credentials (note no port required in server address) 118 | neo_server <- list(address = "bolt://neo.server.address", uid = "neo4j", pwd = "password") 119 | 120 | # csv data file to be loaded onto 'Neo4J' server (path relative to current working directory) 121 | datafile <- "data.csv" 122 | 123 | # CQL query to write data from datafile to 'Neo4J' 124 | loadcsv_CQL <- "LOAD CSV FROM 'file:///data.csv' etc etc;" 125 | 126 | # path to import directory on remote 'Neo4J' server (should be relative to user home directory on remote server) 127 | impdir <- "./import" 128 | 129 | # import data 130 | neo4jshell::neo4j_import(con = neo_server, source = datafile, import_dir = impdir) 131 | 132 | # write data to 'Neo4J' (assumes cypher-shell is in system PATH variable) 133 | neo4jshell:neo4j_query(con = neo_server, qry = loadcsv_CQL) 134 | 135 | # remove data file as clean-up 136 | neo4jshell::neo4j_rmfiles(con = neo_server, files = datafile, import_dir = impdir) 137 | 138 | In Windows, the ‘cypher-shell’ executable may need to be specified with 139 | the file extension, for example `shell_path = "cypher-shell.bat"`. 140 | 141 | ### Local Development 142 | 143 | If you are working with the ‘Neo4J’ server locally, below will help you 144 | get started. 145 | 146 | First, the code below is relative to user and is using ‘Neo4J 4.0.4 147 | Community’ installed at my user’s root. The directory containing the 148 | ‘cypher-shell’ and ‘neo4j’ executables are in my system’s PATH 149 | environment variables. 150 | 151 | ``` r 152 | ## start the local server 153 | neo4j_start() 154 | #> Directories in use: 155 | #> home: /Users/keithmcnulty/neo4j-community-4.0.4 156 | #> config: /Users/keithmcnulty/neo4j-community-4.0.4/conf 157 | #> logs: /Users/keithmcnulty/neo4j-community-4.0.4/logs 158 | #> plugins: /Users/keithmcnulty/neo4j-community-4.0.4/plugins 159 | #> import: /Users/keithmcnulty/neo4j-community-4.0.4/import 160 | #> data: /Users/keithmcnulty/neo4j-community-4.0.4/data 161 | #> certificates: /Users/keithmcnulty/neo4j-community-4.0.4/certificates 162 | #> run: /Users/keithmcnulty/neo4j-community-4.0.4/run 163 | #> Neo4j is already running (pid 2103). 164 | #> [1] 0 165 | 166 | ## setup connection credentials and import directory location 167 | neo_con <- list(address = "bolt://localhost:7687", uid = "neo4j", pwd = "password") 168 | import_loc <- path.expand("~/neo4j-community-4.0.4/import/") 169 | ``` 170 | 171 | First we save `mtcars` to a `.csv` file, and we compress that file. This 172 | package supports a number of delivery formats, but we use a `.zip` file 173 | as an example. 174 | 175 | ``` r 176 | mtcars <- mtcars %>% 177 | tibble::rownames_to_column(var = "model") 178 | 179 | write.csv(mtcars, "mtcars.csv", row.names = FALSE) 180 | zip("mtcars.zip", "mtcars.csv") 181 | ``` 182 | 183 | Now we use `neo4j_import()` to place a **copy** of this file within the 184 | import directory you defined in `import_loc` above. 185 | 186 | ``` r 187 | neo4j_import(local = TRUE, graph, source = "mtcars.zip", import_dir = import_loc) 188 | #> Import and unzip successful! Zip file has been removed! 189 | ``` 190 | 191 | We now write a CQL query to write some information from `mtcars.csv` to 192 | the graph, and execute that query. 193 | 194 | ``` r 195 | CQL <- "LOAD CSV WITH HEADERS FROM 'file:///mtcars.csv' AS row 196 | WITH row WHERE row.model IS NOT NULL 197 | MERGE (c:Car {name: row.model});" 198 | 199 | neo4j_query(neo_con, CQL) 200 | #> Query succeeded with a zero length response from Neo4J 201 | ``` 202 | 203 | Now, let’s remove the `mtcars.csv` file from the import directory of our 204 | local server as cleanup. If you want to use a sub-directory to help 205 | manage your files during an ETL into ‘Neo4J’, you can remove that local 206 | sub-directory when your process has completed using `neo4j_rmdir()`. 207 | 208 | ``` r 209 | ## remove the file 210 | neo4j_rmfiles(local = TRUE, graph, files="mtcars.csv", import_dir = import_loc) 211 | #> Files removed successfully! 212 | ``` 213 | 214 | Now let’s run a query to check the data was loaded to the graph. 215 | 216 | ``` r 217 | CQL <- "MATCH (c:Car) RETURN c.name as name LIMIT 5;" 218 | 219 | neo4j_query(neo_con, CQL) 220 | #> name 221 | #> 1 Mazda RX4 222 | #> 2 Mazda RX4 Wag 223 | #> 3 Datsun 710 224 | #> 4 Hornet 4 Drive 225 | #> 5 Hornet Sportabout 226 | ``` 227 | 228 | ### Local server administration and control 229 | 230 | - `neo4j_start()` starts a local ‘Neo4J’ instance 231 | - `neo4j_stop()` stops a local ‘Neo4J’ instance 232 | - `neo4j_restart()` restarts a local ‘Neo4J’ instance 233 | - `neo4j_status()` returns the status of a local ‘Neo4J’ instance 234 | - `neo4j_wipe()` wipes an entire graph from a local ‘Neo4J’ instance 235 | 236 | For example: 237 | 238 | ``` r 239 | 240 | # my server was already running, confirm 241 | neo4j_status() 242 | #> Neo4j is running at pid 2103 243 | #> [1] 0 244 | 245 | # stop the server 246 | neo4j_stop() 247 | #> Stopping Neo4j....... stopped 248 | #> [1] 0 249 | 250 | # restart 251 | neo4j_start() 252 | #> Directories in use: 253 | #> home: /Users/keithmcnulty/neo4j-community-4.0.4 254 | #> config: /Users/keithmcnulty/neo4j-community-4.0.4/conf 255 | #> logs: /Users/keithmcnulty/neo4j-community-4.0.4/logs 256 | #> plugins: /Users/keithmcnulty/neo4j-community-4.0.4/plugins 257 | #> import: /Users/keithmcnulty/neo4j-community-4.0.4/import 258 | #> data: /Users/keithmcnulty/neo4j-community-4.0.4/data 259 | #> certificates: /Users/keithmcnulty/neo4j-community-4.0.4/certificates 260 | #> run: /Users/keithmcnulty/neo4j-community-4.0.4/run 261 | #> Starting Neo4j. 262 | #> Started neo4j (pid 12838). It is available at http://localhost:7474/ 263 | #> There may be a short delay until the server is ready. 264 | #> See /Users/keithmcnulty/neo4j-community-4.0.4/logs/neo4j.log for current status. 265 | #> [1] 0 266 | 267 | # give it a few seconds to fire up 268 | Sys.sleep(10) 269 | 270 | # query again 271 | neo4j_query(neo_con, qry="MATCH (c:Car) RETURN c.name as name LIMIT 5;") 272 | #> name 273 | #> 1 Mazda RX4 274 | #> 2 Mazda RX4 Wag 275 | #> 3 Datsun 710 276 | #> 4 Hornet 4 Drive 277 | #> 5 Hornet Sportabout 278 | ``` 279 | 280 | If you are using an admin account and you are using ‘Neo4J 4+’ you can 281 | check what databases are available by querying the system database. 282 | 283 | ``` r 284 | neo4j_query(neo_con, qry="SHOW DATABASES;", database = "system") 285 | #> name address role requestedStatus currentStatus error default 286 | #> 1 neo4j localhost:7687 standalone online online TRUE 287 | #> 2 system localhost:7687 standalone online online FALSE 288 | ``` 289 | -------------------------------------------------------------------------------- /man/neo4j_import.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/neo4j_import.R 3 | \name{neo4j_import} 4 | \alias{neo4j_import} 5 | \title{Imports a csv or a compressed file to Neo4J import folder.} 6 | \usage{ 7 | neo4j_import( 8 | local = FALSE, 9 | con = list(address = NULL, uid = NULL, pwd = NULL), 10 | source = NULL, 11 | import_dir = "import", 12 | unzip_path = "unzip", 13 | gunzip_path = "gunzip", 14 | tar_path = "tar" 15 | ) 16 | } 17 | \arguments{ 18 | \item{local}{Logical indicating whether import is to a locally hosted or a remotely hosted server.} 19 | 20 | \item{con}{If remotely hosted server, list containing three objects: address, uid, pwd as character strings providing connection to the Neo4J server. 21 | uid and pwd must be for an account on the server with appropriate permissions.} 22 | 23 | \item{source}{Character string of local path to the csv, zip or tar.gz compressed csv file to be imported} 24 | 25 | \item{import_dir}{Character string of full path to the Neo4J import directory} 26 | 27 | \item{unzip_path}{Path to unzip on the local or remote server to be passed to the system command if necessary.} 28 | 29 | \item{gunzip_path}{Path to gunzip on the local or remote server to be passed to the system command following import if necessary.} 30 | 31 | \item{tar_path}{Path to tar on the local or remote server to be passed to the system command following import if necessary.} 32 | } 33 | \value{ 34 | System messages confirming success or error. zip or tar files will be removed after import and decompression. 35 | } 36 | \description{ 37 | Imports a csv or a compressed file to Neo4J import folder. 38 | } 39 | \examples{ 40 | # import zip to local import directory, with zip in the local system PATH variable 41 | write.csv(mtcars, "mtcars.csv") 42 | zip("mtcars.zip", "mtcars.csv") 43 | fs::dir_create("import") 44 | neo4j_import(local = TRUE, source = "mtcars.zip") 45 | fs::file_delete("mtcars.zip") 46 | fs::file_delete("mtcars.csv") 47 | fs::dir_delete("import") 48 | } 49 | -------------------------------------------------------------------------------- /man/neo4j_query.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/neo4j_query.R 3 | \name{neo4j_query} 4 | \alias{neo4j_query} 5 | \title{Execute a query string in Neo4J using cypher-shell and capture output} 6 | \usage{ 7 | neo4j_query( 8 | con = list(address = NULL, uid = NULL, pwd = NULL), 9 | qry = NULL, 10 | shell_path = "cypher-shell", 11 | database = NULL, 12 | encryption = c("default", "true", "false") 13 | ) 14 | } 15 | \arguments{ 16 | \item{con}{List containing three objects: bolt address, uid, pwd as character strings providing connection to the Neo4J server} 17 | 18 | \item{qry}{Character string of the query or queries to be sent to Neo4J. Read queries should be single queries.} 19 | 20 | \item{shell_path}{If cypher-shell is not in the PATH system variable, the full local path to cypher-shell executable.} 21 | 22 | \item{database}{The name of the database if other than the default database. (For multi-tenancy installations).} 23 | 24 | \item{encryption}{Passes encryption argument to cypher-shell if necessary. Older versions of cypher-shell may require 'true' or 'false' to be passed.} 25 | } 26 | \value{ 27 | A dataframe of results if the read query is successful. A text string if an error is encountered. 28 | Write queries will return a zero length response if successful. 29 | If multiple read queries were submitted, only the results of the final query will be returned. 30 | } 31 | \description{ 32 | Execute a query string in Neo4J using cypher-shell and capture output 33 | } 34 | \examples{ 35 | # if neo4j exists, start the local server, give it a moment to fire up, and run a query 36 | if (nzchar(Sys.which("neo4j"))) { 37 | neo4j_start() 38 | Sys.sleep(2) 39 | graph <- list(address = "bolt://localhost:7687", uid = "neo4j", pwd = "password") 40 | neo4j_query(con = graph, qry = "MATCH (n) RETURN (n)") 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /man/neo4j_restart.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/neo4j_restart.R 3 | \name{neo4j_restart} 4 | \alias{neo4j_restart} 5 | \title{Restart a local Neo4J database} 6 | \usage{ 7 | neo4j_restart(neo4j_path = "neo4j") 8 | } 9 | \arguments{ 10 | \item{neo4j_path}{Path to the Neo4J executable (usually in the bin directory of the Neo4J installation)} 11 | } 12 | \value{ 13 | System messages 14 | } 15 | \description{ 16 | Restart a local Neo4J database 17 | } 18 | \examples{ 19 | # if neo4j exists, restart local graph with neo4j executable in the system PATH variable 20 | if (nzchar(Sys.which("neo4j"))) { 21 | neo4j_restart() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /man/neo4j_rmdir.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/neo4j_rmdir.R 3 | \name{neo4j_rmdir} 4 | \alias{neo4j_rmdir} 5 | \title{Remove subdirectory and all its contents from the Neo4J import directory} 6 | \usage{ 7 | neo4j_rmdir( 8 | local = FALSE, 9 | con = list(address = NULL, uid = NULL, pwd = NULL), 10 | dir = NULL, 11 | import_dir = "import" 12 | ) 13 | } 14 | \arguments{ 15 | \item{local}{Logical indicating whether import is to a locally hosted or remotely hosted server.} 16 | 17 | \item{con}{If remotely hosted server, list containing three objects: address, uid, pwd as character strings providing connection to the Neo4J server. 18 | uid and pwd must be for an account on the server with appropriate permissions.} 19 | 20 | \item{dir}{Character string of the Neo4J import subdirectory name to be deleted.} 21 | 22 | \item{import_dir}{Character string of path to the Neo4J import directory.} 23 | } 24 | \value{ 25 | A success message if successful. A error message otherwise. 26 | } 27 | \description{ 28 | Remove subdirectory and all its contents from the Neo4J import directory 29 | } 30 | \examples{ 31 | # remove a subdirectory and all its contents from the local import directory 32 | fs::dir_create("import/data") 33 | fs::file_create("import/data/data.csv") 34 | neo4j_rmdir(local = TRUE, dir = "data", import_dir = "import") 35 | fs::dir_delete("import") 36 | } 37 | -------------------------------------------------------------------------------- /man/neo4j_rmfiles.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/neo4j_rmfiles.R 3 | \name{neo4j_rmfiles} 4 | \alias{neo4j_rmfiles} 5 | \title{Remove files from the Neo4J import directory} 6 | \usage{ 7 | neo4j_rmfiles( 8 | local = FALSE, 9 | con = list(address = NULL, uid = NULL, pwd = NULL), 10 | files = NULL, 11 | import_dir = "import" 12 | ) 13 | } 14 | \arguments{ 15 | \item{local}{Logical indicating whether import is to a locally hosted or remotely hosted server.} 16 | 17 | \item{con}{If remotely hosted server, list containing three objects: address, uid, pwd as character strings providing connection to the Neo4J server. 18 | uid and pwd must be for an account on the server with appropriate permissions.} 19 | 20 | \item{files}{Character vector of file names to be removed.} 21 | 22 | \item{import_dir}{Character string of path to the Neo4J import directory.} 23 | } 24 | \value{ 25 | A success message if successful. An error message otherwise. 26 | } 27 | \description{ 28 | Remove files from the Neo4J import directory 29 | } 30 | \examples{ 31 | # remove file from local import directory 32 | fs::dir_create("import") 33 | fs::file_create("import/data.csv") 34 | neo4j_rmfiles(local = TRUE, files = "data.csv", import_dir = "import") 35 | fs::dir_delete("import") 36 | } 37 | -------------------------------------------------------------------------------- /man/neo4j_start.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/neo4j_start.R 3 | \name{neo4j_start} 4 | \alias{neo4j_start} 5 | \title{Start a local Neo4J database} 6 | \usage{ 7 | neo4j_start(neo4j_path = "neo4j") 8 | } 9 | \arguments{ 10 | \item{neo4j_path}{Path to the Neo4J executable (usually in the bin directory of the Neo4J installation)} 11 | } 12 | \value{ 13 | System messages 14 | } 15 | \description{ 16 | Start a local Neo4J database 17 | } 18 | \examples{ 19 | # if neo4j exists, start local graph on with neo4j executable in the system PATH variable 20 | if (nzchar(Sys.which("neo4j"))) { 21 | neo4j_start() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /man/neo4j_status.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/neo4j_status.R 3 | \name{neo4j_status} 4 | \alias{neo4j_status} 5 | \title{Check status of a local Neo4J database} 6 | \usage{ 7 | neo4j_status(neo4j_path = "neo4j") 8 | } 9 | \arguments{ 10 | \item{neo4j_path}{Path to the Neo4J executable (usually in the bin directory of the Neo4J installation)} 11 | } 12 | \value{ 13 | System messages 14 | } 15 | \description{ 16 | Check status of a local Neo4J database 17 | } 18 | \examples{ 19 | # if neo4j exists, check status local graph with neo4j executable in the system PATH variable 20 | if (nzchar(Sys.which("neo4j"))) { 21 | neo4j_status() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /man/neo4j_stop.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/neo4j_stop.R 3 | \name{neo4j_stop} 4 | \alias{neo4j_stop} 5 | \title{Stop a local Neo4J database} 6 | \usage{ 7 | neo4j_stop(neo4j_path = "neo4j") 8 | } 9 | \arguments{ 10 | \item{neo4j_path}{Path to the Neo4J executable (usually in the bin directory of the Neo4J installation)} 11 | } 12 | \value{ 13 | System messages 14 | } 15 | \description{ 16 | Stop a local Neo4J database 17 | } 18 | \examples{ 19 | # if neo4j exists, stop local graph with neo4j executable in the system PATH variable 20 | if (nzchar(Sys.which("neo4j"))) { 21 | neo4j_stop() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /man/neo4j_wipe.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/neo4j_wipe.R 3 | \name{neo4j_wipe} 4 | \alias{neo4j_wipe} 5 | \title{Wipe a complete local graph database in Neo4J} 6 | \usage{ 7 | neo4j_wipe(database = NULL, data_path = NULL) 8 | } 9 | \arguments{ 10 | \item{database}{Name of local graph database directory to wipe.} 11 | 12 | \item{data_path}{Path to the local Neo4J data directory} 13 | } 14 | \value{ 15 | Success or error message 16 | } 17 | \description{ 18 | Wipe a complete local graph database in Neo4J 19 | } 20 | \examples{ 21 | # wipe database directory 22 | fs::dir_create("data/databases/foo") 23 | neo4j_wipe(database = "foo", data_path = "data") 24 | fs::dir_delete("data") 25 | } 26 | -------------------------------------------------------------------------------- /neo4jshell.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | -------------------------------------------------------------------------------- /neo4jshell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/keithmcnulty/neo4jshell/08ebf6446554bacdce003a8a11057d1ff55f9a3f/neo4jshell.png -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | *.R 3 | -------------------------------------------------------------------------------- /vignettes/admin.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Server Admin" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Server Admin} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | This package contains functions for administering a local Neo4J server. 18 | 19 | ### Start, stop, restart or check the status of a local Neo4J server 20 | 21 | `neo4J_start()`, `neo4j_stop()`, `neo4j_restart()` and `neo4j_status()` perform a stop, start, restart or reports the current status of a local Neo4J instance. These functions take a single argument `neo4j_path` which should be a path to the local `neo4j` executable. Use `path.expand()` where necessary. 22 | 23 | ```{r example, eval = FALSE} 24 | library(neo4jshell) 25 | 26 | neo_path <- path.expand("~/neo4j-community-4.0.4/bin/neo4j") 27 | neo4j_status(neo_path) 28 | ``` 29 | 30 | All these functions output system messages. 31 | 32 | ### Wipe a specified graph from a local Neo4J server 33 | 34 | `neo4j_wipe()` completely removes a graph from the local Neo4J server. It takes two arguments: 35 | 36 | * `database` is the name of the graph database file to be wiped. 37 | * `data_path` is the path to the data directory of the local Neo4J server. Use `path.expand()` if necessary. 38 | 39 | ``` {r example2, eval = FALSE} 40 | graphfile <- "graph.db" 41 | my_data_path <- path.expand("~/neo4j-community-4.0.4/data") 42 | neo4j_wipe(graphfile, my_data_path) 43 | 44 | ``` 45 | 46 | This function will output a success or an error message. 47 | 48 | ### Note for Windows users 49 | 50 | Paths to executable files that are provided as arguments to functions may need to be provided with appropriate extensions (eg `neo4j.bat`). 51 | -------------------------------------------------------------------------------- /vignettes/files.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Importing and managing data" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Importing and managing data} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | The package provides three functions for importing and managing data with Neo4J. 18 | 19 | ### Importing data 20 | 21 | The function `neo4j_import()` copies a `.csv`, `.zip` or `.tar.gz` file into the specified import directory on the Neo4J server. If the file is compressed, it will automatically decompress the file into the import directory and remove the compressed file afterwards. 22 | 23 | `neo4j_import()` takes the following arguments: 24 | 25 | * `local` should be a logical value indicating if the Neo4J server is locally or remotely hosted. 26 | * `con` should be a list containing three elements: `address`, which should be address of the Neo4J hosting server, and `uid` and `pwd` as login credentials. The bolt address used for querying can be used only if the hosting server uses the same address. Only used if `local = FALSE`. 27 | * `source` is the local path to the file to be imported. Use `path.expand()` if necessary. 28 | * `import_dir` is the local or remote path to the Neo4J import directory. Use `path.expand()` if necessary. 29 | * `unzip_path` is the path to the `unzip` executable on the local or remote server. Only used if a `zip` is imported. 30 | * `gunzip_path` is the path to the `gunzip` executable on the local or remote server. Only used if a `.tar.gz` is imported. 31 | * `tar_path` is the path to the `tar` executable on the local or remote server. Only used if a `.tar.gz` is imported. 32 | 33 | Example, importing a file named `data.csv` to a locally hosted Neo4J server: 34 | 35 | ``` {r, eval = FALSE} 36 | library(neo4jshell) 37 | 38 | file <- "data.csv" # assumes file is present in current working directory 39 | impdir <- path.expand("~/neo4j-community-4.0.4/import") 40 | neo4j_import(local = TRUE, source = file, import_dir = impdir) 41 | 42 | ``` 43 | 44 | The function returns either a success message or an error message. 45 | 46 | ### Removing files from the import directory 47 | 48 | The function `neo4j_rmfiles()` allows the removal of files from the specified Neo4J import directory, which can be useful for cleaning up following import. 49 | 50 | `neo4j_rmfiles()` takes the following arguments: 51 | 52 | * `local` should be a logical value indicating if the Neo4J server is locally or remotely hosted. 53 | * `con` should be a list containing three elements: `address`, which should be the address of the Neo4J hosting server, and `uid` and `pwd` as login credentials. The bolt address used for querying can be used only if the hosting server uses the same address. Only used if `local = FALSE`. 54 | * `source` is a character vector listing the names of the files to be removed from the import directory. 55 | * `import_dir` is the local or remote path to the Neo4J import directory. Use `path.expand()` if necessary. 56 | 57 | Example, removing a file named `data.csv` from a locally hosted Neo4J server: 58 | 59 | ``` {r, eval = FALSE} 60 | library(neo4jshell) 61 | 62 | file <- "data.csv" 63 | impdir <- path.expand("~/neo4j-community-3.5.8/import") 64 | neo4j_rmfiles(local = TRUE, files = file, import_dir = impdir) 65 | 66 | ``` 67 | 68 | The function returns either a success message or an error message. 69 | 70 | ### Removing subdirectories from the import directory 71 | 72 | The function `neo4j_rmdir()` allows the removal of an entire sub-directory and all its contents from the specified Neo4J import directory, which can be useful for cleaning up following import. 73 | 74 | `neo4j_rmdir()` takes the following arguments: 75 | 76 | * `local` should be a logical value indicating if the Neo4J server is locally or remotely hosted. 77 | * `con` should be a list containing three elements: `address`, which should be the address of the Neo4J hosting server, and `uid` and `pwd` as login credentials. The bolt address used for querying can be used only if the hosting server uses the same address. Only used if `local = FALSE`. 78 | * `dir` is the name of the subdirectory of the import directory to be removed. 79 | * `import_dir` is the local or remote path to the Neo4J import directory. Use `path.expand()` if necessary. 80 | 81 | Example, removing a directory called `data` from a locally hosted Neo4J server: 82 | 83 | ``` {r, eval = FALSE} 84 | library(neo4jshell) 85 | 86 | datadir <- "data" 87 | impdir <- path.expand("~/neo4j-community-4.0.4/import") 88 | neo4j_rmdir(local = TRUE, dir = datadir, import_dir = impdir) 89 | 90 | ``` 91 | 92 | The function returns either a success message or an error message. 93 | 94 | ### Smooth ETL in Neo4J 95 | 96 | These functions can be used in combination with `neo4j_query()` to set up smooth ETL on a Neo4J server, by executing in the following order: 97 | 98 | 1. `neo4j_import()` to transfer a data file into the import directory or into a subdirectory (if the compressed file involves a subdirectory). 99 | 2. `neo4j_query()` to execute a load query referencing the imported file. 100 | 3. `neo4j_rmfiles()` or `neo4j_rmdir()` to remove the imported files following a successful load query. 101 | 102 | ### Note for Windows users 103 | 104 | Paths to executable files that are provided as arguments to functions may need to be provided with appropriate extensions (eg `cypher-shell.bat`). 105 | 106 | -------------------------------------------------------------------------------- /vignettes/querying.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Querying Neo4J" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Querying Neo4J} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | The function `neo4j_query()` can be used to send a query to a local or remote Neo4J server. This function uses `cypher-shell` to send the query to Neo4J, and so the `cypher-shell` executable needs to be installed and available locally. See the `README` file for further information on configuration of the `cypher-shell` executable. 18 | 19 | `neo4j_query()` takes the following arguments: 20 | 21 | * `con` should be a list containing three elements: `address`, which should be the bolt address of the Neo4J server, and `uid` and `pwd` as login credentials 22 | * `qry` should be a character string representing the query to be sent to Neo4J 23 | * `shell_path` should be the full path to the `cypher-shell` executable. The default value assumes that `cypher-shell` is already in the system path. Use `path.expand()` if necessary. 24 | * `database` specifies the database to be queried if not the default database. (For multitenancy Neo4J installations). 25 | * `encryption` is the encryption option passed to `cypher-shell`. This may be required as explicitly `'true'` or `'false'` for older installations. 26 | 27 | Example, assuming a local Neo4J instance running the movies graph: 28 | 29 | ```{r example, eval = FALSE} 30 | library(neo4jshell) 31 | 32 | neo4j_local <- list(address = "bolt://localhost", uid = "neo4j", pwd = "password") 33 | CQL <- 'MATCH (p1:Person {name: "Kevin Bacon"})-[:ACTED_IN]->(m:Movie)<-[:DIRECTED]-(p2:Person) 34 | RETURN p2.name AS Name, m.title AS Title' 35 | cypher_path <- path.expand("~/neo4j-community-4.0.4/bin/cypher-shell") 36 | neo4j_query(con = neo4j_local, qry = CQL, shell_path = cypher_path) 37 | 38 | ``` 39 | 40 | This query should return this dataframe: 41 | 42 | ``` {r example-output, echo = FALSE} 43 | 44 | data.frame(Name = c("Ron Howard", "Rob Reiner", "Ron Howard"), 45 | Title = c("Frost/Nixon", "A Few Good Men", "Apollo 13")) 46 | 47 | ``` 48 | 49 | `neo4j_query()` accepts multiple query statements separated by `;`. The function returns one of the following: 50 | 51 | * A dataframe of results if the query is a read query. If there were multiple statements, only the results of the final statement will display. 52 | * A message indicating successful execution if the query is a write query. 53 | * An error message if an error occurred. If there were multiple statements, the response for all statements will be displayed. 54 | 55 | ### Note for Windows users 56 | 57 | Paths to executable files that are provided as arguments to functions may need to be provided with appropriate extensions (eg `cypher-shell.bat`). 58 | --------------------------------------------------------------------------------