Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Postgres JSON operators? #16

Open
xiongtx opened this issue Mar 28, 2018 · 8 comments
Open

Support for Postgres JSON operators? #16

xiongtx opened this issue Mar 28, 2018 · 8 comments

Comments

@xiongtx
Copy link

xiongtx commented Mar 28, 2018

Is there any interest in adding Postgres JSON functions and operators?

E.g. I've been using the following in my own code:

(require '[clojure.string :as str])
(require '[honeysql.format :as h-format])

(defmethod h-format/fn-handler "->" [_ val index]
  (let [[val index] (map h-format/to-sql [val index])]
    (if (number? index)
      (format "%s->%s" val index)
      (format "%s->'%s'" val index))))

(defmethod h-format/fn-handler "->" [_ val index]
  (let [[val index] (map h-format/to-sql [val index])]
    (if (number? index)
      (format "%s->>%s" val index)
      (format "%s->>'%s'" val index))))

(defmethod h-format/fn-handler "#>" [_ val path]
  (format "%s#>'{%s}'"
          (h-format/to-sql val)
          (->> path
               (map h-format/to-sql)
               (str/join ","))))

This allows us to write e.g.:

(-> (h/select [(sql/call :#> :value [:a :b]) :value])
    (h/from :my_table))

to produce the query SELECT value#>'{a,b}' AS value FROM my_table.

@ukriish
Copy link
Contributor

ukriish commented Mar 29, 2018

That looks like it can come in handy. Please raise a PR and I'll be happy to merge it. :)

@xiongtx
Copy link
Author

xiongtx commented Mar 29, 2018

Will consider a PR after we gain more familiarity w/ using HoneySQL w/ JSONB 😄.

The above is promising, though.

@arichiardi
Copy link
Contributor

Is there any development on this one? I am interested as well and wanted to roll my own in case @xiongtx is busy at the moment..

@ukriish
Copy link
Contributor

ukriish commented Dec 22, 2018

I've been using quite a lot of JSONB in my daily work, sadly not in clojure so haven't had time to work on this. That said, I think this is very useful and would like to add this feature to honeysql-postgres soon.

I can consider working on this in a week or two. I'm away for a week on vacation.

@devn
Copy link

devn commented Jan 2, 2019

I'm interested in this also. I ran into this HN comment while googling, and it looked nice: https://news.ycombinator.com/item?id=17498349

CC: @emidin since I saw him post on the referenced issue: seancorfield/honeysql#159

@devn
Copy link

devn commented Jan 14, 2019

@xiongtx FWIW, one issue with your original snippet is that it doesn't handle nested cases. For instance, a->b->>c, would be nice to represent as (sql/call :->> (sql/call :-> :a :b) :c) or something. (sql/json (:a :-> :b :->> :c)) would be nicer still.

@lsnape
Copy link

lsnape commented Jun 27, 2019

I think this more or less gets you what you want:

(defn json-get
  [val ks as-text?]
  (reduce (fn [acc [k next]]
            (str acc
                 (if (and as-text? (nil? next)) " ->> " " -> ")
                 (if-not (number? k)
                   (format "'%s'" (fmt/to-sql k))
                   k)))
          (fmt/to-sql val)
          (partition-all 2 1 ks)))

(defmethod fmt/fn-handler "->" [_ val ks]
  (json-get val ks false))

(defmethod fmt/fn-handler "->>" [_ val ks]
  (json-get val ks true))

(honey/format
   (-> (hsql/select (honey/call :->> :s.data [:foo :bar]))
       (hsql/from :baz)))

;; ["SELECT s.data -> 'foo' ->> 'bar' FROM foo"]

@SevereOverfl0w
Copy link

For #> instead of using a string/join to build an array literal, an array should be passed instead. This will allow for escaping parameters as required (no sql injection then!)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants