So, if it's not obvious, there is something wrong with our "query" (which is not a query in the normal sense but something we are trying to do).
So let's try something simpler. Last time, I managed to get a very simple "query" to work from the command line:
$ curl https://user-stocks.cluster-ckgvna81hufy.us-east-1.neptune.amazonaws.com:8182/openCypher?query="RETURN%201"So let's see if we can get that working from within the Go program:
{
"results": [{
"1": 1
}]
}
func (nc *NodeCreator) Insert(label string) error {
r1 := "RETURN 1"
insertQuery := neptunedata.ExecuteOpenCypherQueryInput{OpenCypherQuery: aws.String(r1)}
out, err := nc.svc.ExecuteOpenCypherQuery(context.TODO(), &insertQuery)
if err != nil {
return err
}
var results []map[string]any = nil
err = out.Results.UnmarshalSmithyDocument(&results)
if err != nil {
return err
}
for _, m := range results {
for k, v := range m {
log.Printf("result %s => %s\n", k, v)
}
}
return err
}
NEPTUNE_SIMPLER_QUERY:neptune/cmd/create/main.go
The "query" portion of this is really quite simple: we simply pass RETURN 1 as OpenCypherQuery. Processing the response is quite hard, though. The structure is the same as we saw on the command line, so the output value has a Results member. This can only be accessed however, through an inversion-of-control method UnmarshalSmithyDocument (this is described here).In order to get that to work, you need a variable of "the right type". I figured this out by reading the error messages one at a time and fixing one issue at a time. In retrospect, it's possible to look at the output above and see that we have a list of maps. I don't understand enough about how openCypher works yet to understand what all the possibilities are, but suffice it to say that the 1 I wanted to RETURN is the value of the key "1" in the map.
When I run this program, I get this:
2025/07/12 12:06:53 result 1 => 1Excellent.
Creating Nodes
Given that all the examples in the documentation use curl, let's try to do that and then try and back into what we really want. So here's an example from the Neptune manual:$ curl https://user-stocks.cluster-ckgvna81hufy.us-east-1.neptune.amazonaws.com:8182/openCypher -d "query=CREATE (n: Person { age: 25})"So this "works", so let's try that from Go:
{"results":[]}
func (nc *NodeCreator) Insert(label string) error {
r1 := "CREATE (n: Person { age: 25})"
insertQuery := neptunedata.ExecuteOpenCypherQueryInput{OpenCypherQuery: aws.String(r1)}
out, err := nc.svc.ExecuteOpenCypherQuery(context.TODO(), &insertQuery)
if err != nil {
return err
}
NEPTUNE_SIMPLE_CREATE:neptune/cmd/create/main.go
And, as you would expect, there is no output, since there are no return values (and no error).Parameters
We want to create nodes with parameters, so let's try that.Parameterized queries are described in a separate section of the manual, and there are no examples using create. But we can adapt one of the match queries to our endpoint and try this:
$ curl -k https://user-stocks.cluster-ckgvna81hufy.us-east-1.neptune.amazonaws.com:8182/openCypher -d "query=MATCH (n {name: \name, age: \age}) RETURN n" -d "parameters={\"name\": \"john\", \"age\": 20}"Now, having come this far, I'm disappointed not to see any results. So, given that we created a node above, before we convert this to Go, I'm going to try actually obtaining a match.
{"results":[]}
$ curl -k https://user-stocks.cluster-ckgvna81hufy.us-east-1.neptune.amazonaws.com:8182/openCypher -d "query=MATCH (n {age: \$age}) RETURN n" -d "parameters={\"age\": 25}"I have to admit, I'm somewhat surprised to have three results here, but that is presumably because I ran three different commands to insert (the same) record.
{
"results": [{
"n": {
"~id": "dfe31b9c-0925-4744-bfc8-15b233cf4f48",
"~entityType": "node",
"~labels": ["Person"],
"~properties": {
"age": 25
}
}
}, {
"n": {
"~id": "f7fe6f4c-22cd-4d3e-9bbc-9dd755d5918d",
"~entityType": "node",
"~labels": ["Person"],
"~properties": {
"age": 25
}
}
}, {
"n": {
"~id": "7510e8e0-36be-42e1-a18c-584d1e3e5b34",
"~entityType": "node",
"~labels": ["Person"],
"~properties": {
"age": 25
}
}
}]
}
Right, let's do that in Go. The tricky thing is figuring out which of the quotes and backslashes above are just for the shell and which are needed, but after a couple of tries I came up with this, which seems to work:
func (nc *NodeCreator) Insert(label string) error {
r1 := "MATCH (n {age: $age}) RETURN n"
params := `{"age": 25}`
insertQuery := neptunedata.ExecuteOpenCypherQueryInput{OpenCypherQuery: aws.String(r1), Parameters: aws.String(params)}
out, err := nc.svc.ExecuteOpenCypherQuery(context.TODO(), &insertQuery)
if err != nil {
return err
}
NEPTUNE_PARAM_MATCH:neptune/cmd/create/main.go
2025/07/12 12:45:11 result n => map[~entityType:node ~id:dfe31b9c-0925-4744-bfc8-15b233cf4f48 ~labels:[Person] ~properties:map[age:25]]
2025/07/12 12:45:11 result n => map[~entityType:node ~id:f7fe6f4c-22cd-4d3e-9bbc-9dd755d5918d ~labels:[Person] ~properties:map[age:25]]
2025/07/12 12:45:11 result n => map[~entityType:node ~id:7510e8e0-36be-42e1-a18c-584d1e3e5b34 ~labels:[Person] ~properties:map[age:25]]
Finally Back to Creation
So, with all that in the bag, let's go back and try and do a parameterized creation in Neptune. Again, it took a couple of goes to get where I wanted to be, but this does work:func (nc *NodeCreator) Insert(label string) error {
create := "CREATE (n:stock {symbol: $symbol})"
params := fmt.Sprintf(`{"symbol": "%s"}`, label)
insertQuery := neptunedata.ExecuteOpenCypherQueryInput{OpenCypherQuery: aws.String(create), Parameters: aws.String(params)}
out, err := nc.svc.ExecuteOpenCypherQuery(context.TODO(), &insertQuery)
if err != nil {
return err
}
NEPTUNE_CREATE_STOCK:neptune/cmd/create/main.go
And I can run a query from the command line that checks that the entry was inserted.
No comments:
Post a Comment