gorillalabs / neo4j-clj

Clojure bindings for Bolt / the Java Neo4j driver, complete with Joplin support for managing database migrations.
MIT License
90 stars 14 forks source link

How to deal with quoted strings in the Cypher query from the clojure repl #11

Closed abhi18av closed 6 years ago

abhi18av commented 6 years ago

Hi gorillalabs team :)

I'm really enjoying using this library so far, with one exception of not being able to deal with the quoted strings properly.

Building on the example in the ReadMe, I've added a node to the database

(with-open [session (db/get-session local-db)]
  (create-user session {:user {:firstName "Anakin" :middleName "\"Darth Vader\"" :lastName "Skywalker"}}))

What I'd like to do is that

(db/with-transaction local-db tx
  ("MATCH (user {middleName: "\"Darth Vader\""}) RETURN user" tx)) ;; => ({:user {:first-name "Luke", :last-name "Skywalker"}}))

But I'm unable to do so, I've tried various enumerations of """Darth Vader""" / ' "Darth Vader" ' etc but with no success so far.

Could you please guide me a bit here ?

Also, I'd like to note that the kebab-sytle in the variable/field names are problematic in terms of the example

chrisbetz commented 6 years ago

Hi,

you're right about the kebab-style. I'll change that.

With your code, there are several points not quite right in your code.

First, you cannot just put a string in parentheses to make it a query. You actually need to build a query-function from that using defquery.

(db/defquery get-all-users
  "MATCH (u:user) RETURN u as user")

So you should use something like this

(db/defquery get-users-by-middlename
  "MATCH (u:User {middleName: $middleName}) RETURN u as user")

and call it like this

(get-users-by-middlename tx {:middleName "\"Darth Vader\""})

Second, in your example, you broke the string.

"MATCH (user {middleName: "\"Darth Vader\""}) RETURN user"

I'm pretty sure that's just a copy-paste-error.

But, if you evaluate just that in your REPL, you'll see something similar to that:

RuntimeException Unsupported character: \"Darth  clojure.lang.Util.runtimeException (Util.java:221)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: Vader in this context, compiling:(/private/var/folders/33/14_bmfhn22j3vjphs2zd0rdh0000gn/T/form-init7087298943626981370.clj:1:726) 

You wanted to write something like this:

"MATCH (user {middleName: \"Darth Vader\"}) RETURN user"
abhi18av commented 6 years ago

Hi @chrisbetz

I did make some progress with the examples but I'm running into a similar problem still.

The problem I'm facing is with this part

(db/defquery get-users-by-middlename
  "MATCH (u:User {middleName: $middleName}) RETURN u as user")

(db/with-transaction local-db tx
;(get-users-by-middlename tx {:middleName "Darth Vader"}))
  (get-users-by-middlename tx {:middleName "\"Darth Vader\""}))

(db/defquery get-users-by-firstname
  "MATCH (u:User {firstName: $firstName}) RETURN u as user")

(db/with-transaction local-db tx
  (get-users-by-firstname tx {:firstName "Anakin"}))

I've tried out the solutions you highlighted but the quoted strings are still sticky.

And here's the entire scratch file

(require '[neo4j-clj.core :as db])

;; first of all, connect to a Neo4j instance using URL, user and password credentials.
;; Remember not to check in credentials into source code repositories, but use environment variables
;; instead.

(def local-db
  (db/connect "bolt://localhost:7687" "neo4j" "password"))

(db/defquery delete-all-users
  "match (u:user) delete u")

;; Using a transaction
(db/with-transaction local-db tx
  (delete-all-users tx))

;; We're big fans of using Strings to represent Cypher queries, and not wrap Cypher into some
;; other data structure to make things more complicated then necessary. So simply defquery your query...

(db/defquery create-user
  "CREATE (u:user $user)")

;; ... and you'll get a function `create-user` to call with a session and the parameters. See below.

;; Define any other queries you'll need. I'd suggest to keep all the Cypher queries in a separate namespace,
;; but hey, that's up to you.

;; Using a session
(with-open [session (db/get-session local-db)]
  (create-user session {:user {:firstName "Anakin" :middleName "Darth Vader" :lastName "Skywalker"}}))

;; Using a session
(with-open [session (db/get-session local-db)]
  (create-user session {:user {:firstName "Luke" :lastName "Skywalker"}}))

;; Using a session
(with-open [session (db/get-session local-db)]
  (create-user session {:user {:firstName "Babu" :middleName '"Artengo" ':lastName "Fett"}}))

;; Using a session
(with-open [session (db/get-session local-db)]
  (create-user session {:user {:firstName "Boba" :middleName '"Django" ':lastName "Fett"}}));; Using a transaction

(db/defquery get-all-users
  "MATCH (u:user) RETURN u as user")

(db/with-transaction local-db tx
  (get-all-users tx)) ;; => ({:user {:first-name "Luke", :last-name "Skywalker"}}))

;;;;

(db/defquery get-users-by-middlename
  "MATCH (u:User {middleName: $middleName}) RETURN u as user")

(db/with-transaction local-db tx
;(get-users-by-middlename tx {:middleName "Darth Vader"}))
  (get-users-by-middlename tx {:middleName "\"Darth Vader\""}))

(db/defquery get-users-by-firstname
  "MATCH (u:User {firstName: $firstName}) RETURN u as user")

(db/with-transaction local-db tx
  (get-users-by-firstname tx {:firstName "Anakin"}))

;;;;

(db/defquery get-darth-vader
  "MATCH (user {middleName: \"Darth Vader\"}) RETURN user")

(db/with-transaction local-db tx
  (get-darth-vader tx))
chrisbetz commented 6 years ago

Not sure what you're expecting.

You created the "Anakin"-node without quotes in the middlename, but you query for a string including quotes. That will not return anything...?

(with-open [session (db/get-session local-db)]
  (create-user session {:user {:firstName "Anakin" :middleName "Darth Vader" :lastName "Skywalker"}}))

and

(db/with-transaction local-db tx
;(get-users-by-middlename tx {:middleName "Darth Vader"}))
  (get-users-by-middlename tx {:middleName "\"Darth Vader\""}))

That'l return an empty list.

It will however if you query for a string without quotes, as you did in your last query:

(db/defquery get-darth-vader
             "MATCH (user {middleName: \"Darth Vader\"}) RETURN user")

(db/with-transaction local-db tx
                     (get-darth-vader tx))

This will return a list with your Anakin-node.

Also, I'm not sure about your usage of single quotes (:middleName '"Django" ':lastName "Fett")

abhi18av commented 6 years ago

Hmm, so I've am experimenting some more and I think that this is how I'd summarize the main issue now

Given that :


(with-open [session (db/get-session local-db)]
  (create-user session {:user {:firstName "Anakin" :middleName "Darth Vader" :lastName "Skywalker"}}))

This works perfectly fine

(db/defquery get-darth-vader
  "MATCH (user {middleName: \"Darth Vader\"}) RETURN user")

(db/with-transaction local-db tx
  (get-darth-vader tx))

But this doens't work, I've commented out the various options here.

(db/defquery get-users-by-middlename
  "MATCH (u:User {middleName: $middleName}) RETURN u as user")

(db/with-transaction local-db tx
  ;(get-users-by-middlename tx {:middleName "Darth Vader"}))
  ;(get-users-by-middlename tx {:middleName """Darth Vader"""}))
  ;(get-users-by-middlename tx {:middleName "\"Darth Vader\""}))

I do appreciate your patient help @chrisbetz πŸ‘

chrisbetz commented 6 years ago

You're creating your users with a lowercase label "user"

(db/defquery create-user
  "CREATE (u:user $user)")

In your working query, you do not specify a label at all, so everything's fine.

In your latter query, you are querying for a user with an uppercase label User. This won't return a thing no matter what other filters you apply.

So, if you correct that to

(db/defquery get-users-by-middlename
  "MATCH (u:user {middleName: $middleName}) RETURN u as user")

then

(db/with-transaction local-db tx
  (prn (get-users-by-middlename tx {:middleName "Darth Vader"}))
  (prn (get-users-by-middlename tx {:middleName """Darth Vader"""}))
  (prn (get-users-by-middlename tx {:middleName "\"Darth Vader\""})))

will print

({:user {:firstName "Anakin", :lastName "Skywalker", :middleName "Darth Vader"}})
()
()

just as it should. Your node in Neo4j doesn't have a quoted middle name.

abhi18av commented 6 years ago

@chrisbetz πŸ₯‡ πŸ˜ƒ

All solved!

Thank you so so much πŸ‘

chrisbetz commented 6 years ago

Youβ€˜re welcome.

Keep on hacking ;)

Am 02.07.2018 um 16:09 schrieb Abhinav Sharma notifications@github.com:

@chrisbetz πŸ₯‡ πŸ˜ƒ

All solved!

Thank you so so much πŸ‘

β€” You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.