Skip to content

Commit 7304622

Browse files
committed
Support query parameters
1 parent 3130cf3 commit 7304622

File tree

2 files changed

+56
-28
lines changed

2 files changed

+56
-28
lines changed

scripts/executeQuery.sh

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
#!/usr/bin/env bash
22

33
# Utilizes Neo4j's HTTP API to execute a Cypher query from an input file and provides the results in CSV format.
4-
# Use it when "cypher-shell" is not present or not flexible enough.
4+
# Use it when "cypher-shell" is not present, not flexible enough or to avoid an additional dependency.
55

66
# It requires "cURL" ( https://curl.se ) and "jq" ( https://stedolan.github.io/jq ) to be installed.
77
# The environment variable NEO4J_INITIAL_PASSWORD needs to be set.
88

99
# Using "cypher-shell" that comes with Neo4j server is much simpler to use:
10-
# cat $cypher_query_file_name | $NEO4J_HOME/bin/cypher-shell -u neo4j -p password --format plain
10+
# cat $cypher_query_file_name | $NEO4J_HOME/bin/cypher-shell -u neo4j -p password --format plain --param "number ⇒ 3"
1111

1212
# Note: These command line arguments are supported:
1313
# -> "filename" of the cypher query file (required, unnamed first argument)
1414
# -> "--no_source_reference" to not append the cypher query file name as last CSV column
15+
# -> any following key=value arguments are used as query parameters
1516

1617
# Overrideable Defaults
1718
NEO4J_HTTP_PORT=${NEO4J_HTTP_PORT:-"7474"} # Neo4j HTTP API port for executing queries
@@ -26,6 +27,7 @@ fi
2627
# Input Arguments: Initialize arguments and set default values for optional ones
2728
cypher_query_file_name=""
2829
no_source_reference=false
30+
query_parameters=""
2931

3032
# Input Arguments: Function to print usage information
3133
print_usage() {
@@ -36,17 +38,17 @@ print_usage() {
3638

3739
# Input Arguments: Parse the command-line arguments
3840
while [[ $# -gt 0 ]]; do
39-
key="$1"
41+
arg="$1"
4042

41-
case $key in
43+
case $arg in
4244
--no-source-reference-column)
4345
no_source_reference=true
4446
shift
4547
;;
4648
*)
47-
if [[ -z "$cypher_query_file_name" ]]; then
49+
if [[ -z "${cypher_query_file_name}" ]]; then
4850
# Input Arguments: Read the first unnamed input argument containing the name of the cypher file
49-
cypher_query_file_name="$key"
51+
cypher_query_file_name="${arg}"
5052
#echo "Cypher File: $cypher_query_file_name"
5153

5254
# Input Arguments: Check the first input argument to be a valid file
@@ -56,18 +58,26 @@ while [[ $# -gt 0 ]]; do
5658
exit 1
5759
fi
5860
else
59-
echo "Error: Unknown option: $key" >&2
60-
print_usage
61-
exit 1
61+
# Convert key=value argument to JSON "key": "value" and strip all incoming quotes first
62+
json_parameter=$(echo "${arg}" | sed "s/[\"\']//g" | awk -F'=' '{ print "\""$1"\": \""$2"\""}'| grep -iv '\"#')
63+
if [[ -z "${query_parameters}" ]]; then
64+
# Add first query parameter directly
65+
query_parameters="${json_parameter}"
66+
else
67+
# Append next query parameter separated by a comma and a space
68+
query_parameters="${query_parameters}, ${json_parameter}"
69+
fi
6270
fi
6371
shift
6472
;;
6573
esac
6674
done
6775

76+
#echo "executeQuery: query_parameters: ${query_parameters}"
77+
6878
# Read the file that contains the Cypher query
6979
original_cypher_query=$(<"${cypher_query_file_name}")
70-
#echo "Original Query: $original_cypher_query"
80+
#echo "executeQuery: Original Query: $original_cypher_query"
7181

7282
# Encode the string containing the Cypher query to be used inside JSON using jq ( https://stedolan.github.io/jq )
7383
# Be sure to put double quotes around the original Cypher query to prevent newlines from beeing removed.
@@ -77,11 +87,11 @@ original_cypher_query=$(<"${cypher_query_file_name}")
7787
# . means "output the root of the JSON document"
7888
# Source: https://stackoverflow.com/questions/10053678/escaping-characters-in-bash-for-json
7989
cypher_query=$(echo -n "${original_cypher_query}" | jq -Rsa .)
80-
#echo "Cypher Query: $cypher_query"
90+
#echo "executeQuery: Cypher Query JSON Encoded: $cypher_query"
8191

8292
# Put the query inside the structure that is expected by the Neo4j HTTP API
83-
cypher_query_for_api="{\"statements\":[{\"statement\":${cypher_query},\"includeStats\": false}]}"
84-
#echo "Cypher Query for API: ${cypher_query_for_api}"
93+
cypher_query_for_api="{\"statements\":[{\"statement\":${cypher_query},\"parameters\":{${query_parameters}},\"includeStats\": false}]}"
94+
#echo "executeQuery: Cypher Query for API: ${cypher_query_for_api}"
8595

8696
# Calls the Neo4j HTTP API using cURL ( https://curl.se )
8797
cyper_query_result=$(curl --silent -S --fail-with-body -H Accept:application/json -H Content-Type:application/json \

scripts/executeQueryFunctions.sh

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,34 +12,28 @@ SCRIPTS_DIR=${SCRIPTS_DIR:-$( CDPATH=. cd -- "$(dirname -- "${BASH_SOURCE[0]}")"
1212

1313
# Function to execute a cypher query from the given file (first argument) with the default method
1414
execute_cypher() {
15-
execute_cypher_http "${1}" || exit 1
15+
execute_cypher_http "${@}" || exit 1 # "${@}": Get all function arguments and forward them
1616
}
1717

1818
# Function to execute a cypher query from the given file (first argument) with the default method and just return the number of results
1919
execute_cypher_summarized() {
20-
execute_cypher_http_summarized "${1}" || exit 1
20+
execute_cypher_http_summarized "${@}" || exit 1 # "${@}": Get all function arguments and forward them
2121
}
2222

2323
# Function to execute a cypher query from the given file (first argument) with the default method and fail if there is no result
2424
execute_cypher_expect_results() {
25-
execute_cypher_http_expect_results "${1}" || exit 1
25+
execute_cypher_http_expect_results "${@}" || exit 1 # "${@}": Get all function arguments and forward them
2626
}
2727

2828
# Function to execute a cypher query from the given file (first and only argument) using Neo4j's HTTP API
2929
execute_cypher_http() {
30-
# Get the Cypher file name from the first argument
31-
cypherFileName="${1}"
32-
3330
# (Neo4j HTTP API Script) Execute the Cyper query contained in the file and print the results as CSV
34-
source $SCRIPTS_DIR/executeQuery.sh "${cypherFileName}" || exit 1
31+
source $SCRIPTS_DIR/executeQuery.sh "${@}" || exit 1 # "${@}": Get all function arguments and forward them
3532
}
3633

3734
# Function to execute a cypher query from the given file (first and only argument) with a summarized (console) output using Neo4j's HTTP API
3835
execute_cypher_http_summarized() {
39-
# Get the Cypher file name from the first argument
40-
cypherFileName="${1}"
41-
42-
results=$( execute_cypher_http ${cypherFileName} | wc -l )
36+
results=$( execute_cypher_http "${@}" | wc -l ) # "${@}": Get all function arguments and forward them
4337
results=$((results - 2))
4438
echo "$(basename -- "${cypherFileName}") (via http) result lines: ${results}"
4539
}
@@ -57,19 +51,43 @@ execute_cypher_http_expect_results() {
5751
fi
5852
}
5953

54+
cypher_shell_query_parameters() {
55+
query_parameters=""
56+
shift # ignore first argument containing the query file name
57+
58+
while [[ $# -gt 0 ]]; do
59+
arg="${1}"
60+
# Convert key=value argument to JSON "key": "value"
61+
json_parameter=$(echo "${arg}" | awk -F'=' '{print ""$1": "$2""}'| grep -iv '\"#')
62+
if [[ -z "${query_parameters}" ]]; then
63+
# Add first query parameter directly
64+
query_parameters="${json_parameter}"
65+
else
66+
# Append next query parameter separated by a comma and a space
67+
query_parameters="${query_parameters}, ${json_parameter}"
68+
fi
69+
shift # iterate to next argument
70+
done
71+
echo "{${query_parameters}}"
72+
}
73+
6074
# Function to execute a cypher query from the given file (first and only argument) using "cypher-shell" provided by Neo4j
6175
execute_cypher_shell() {
6276
# Get the Cypher file name from the first argument
63-
cypherFileName=$1
77+
cypherFileName="${1}"
6478

6579
# Check if NEO4J_BIN exists
6680
if [ ! -d "${NEO4J_BIN}" ] ; then
6781
echo "executeQuery: Error: Neo4j Binary Directory <${NEO4J_BIN}> doesn't exist. Please run setupNeo4j.sh first." >&2
6882
exit 1
6983
fi
7084

85+
# Extract query parameters out of the key=value pair arguments that follow the first argument (query filename)
86+
query_parameters=$(cypher_shell_query_parameters "${@}")
87+
echo "executeQuery: query_parameters=${query_parameters}"
88+
7189
# (Neo4j Cyper Shell CLI) Execute the Cyper query contained in the file and print the results as CSV
72-
cat $cypherFileName | NEO4J_HOME="${NEO4J_DIRECTORY}" ${NEO4J_BIN}/cypher-shell -u neo4j -p "${NEO4J_INITIAL_PASSWORD}" --format plain || exit 1
90+
cat $cypherFileName | NEO4J_HOME="${NEO4J_DIRECTORY}" ${NEO4J_BIN}/cypher-shell -u neo4j -p "${NEO4J_INITIAL_PASSWORD}" --format plain --param "${query_parameters}" || exit 1
7391

7492
# Display the name of the Cypher file without its path at the bottom of the CSV (or console) separated by an empty line
7593
# TODO Find a solution to move the source reference to the last column name
@@ -80,7 +98,7 @@ execute_cypher_shell() {
8098
# Function to execute a cypher query from the given file (first and only argument) with a summarized (console) output using "cypher-shell" provided by Neo4j
8199
execute_cypher_shell_summarized() {
82100
# Get the Cypher file name from the first argument
83-
cypherFileName=$1
101+
cypherFileName="${1}"
84102

85103
results=$( execute_cypher_shell ${cypherFileName} | wc -l )
86104
results=$((results - 2))
@@ -90,7 +108,7 @@ execute_cypher_shell_summarized() {
90108
# Function to execute a cypher query from the given file (first and only argument) that fails on no result using "cypher-shell" provided by Neo4j
91109
execute_cypher_shell_expect_results() {
92110
# Get the Cypher file name from the first argument
93-
cypherFileName=$1
111+
cypherFileName="${1}"
94112

95113
results=$( execute_cypher_shell ${cypherFileName} | wc -l )
96114
results=$((results - 2))

0 commit comments

Comments
 (0)