Makoto
Makoto

Reputation: 106430

Expressing (parameterized) ANY(array) query for Postgres in SQLKorma

I'm currently using SQLKorma for a project, and I'm running into a bit of a snag with it.

I have constructed a query with two left-joins; one of them contains an array with entries that I wish to use in my WHERE clause.

This is trivial to express in SQL. Note that this is a primarily redacted query.

SELECT
  cu.name,
  c.description,
  c.created_at AT TIME ZONE 'utc'
FROM calendar_users cu LEFT JOIN calendars c ON cu.id = c.user_id
  LEFT JOIN meetings m ON c.id = m.id
WHERE 'status_report' ILIKE ANY (m.meeting_metadata)
GROUP BY m.meeting_metadata, c.created_at, cu.name, cu.description
ORDER BY c.created_at DESC

The portion in regards to ILIKE ANY is what I'd like to be able to translate to Korma.

I understand from the docs that the ANY clause isn't supported from the WHERE clause, and I should look into using raw or exec-raw instead.

With that, I want to pass in a parameterized raw string into the WHERE clause to accomplish what I'm trying to go for.

This I've attempted, but it does fails with a syntax error in Postgres:

(select calendars
    (fields calendar-user-cols)
    (join :calendar_users (= :calendars.user_id :calendar_users.id))
    (join :meetings (= :calendars.id :meetings.id))
    (where (raw ["? ILIKE ANY(meetings.meeting_metadata)" metadata])))

Specifically:

PSQLException:
 Message: ERROR: syntax error at or near "["
  Position: 1006
 SQLState: 42601
 Error Code: 0

How would I go about this using Korma? Do I have to resort to a full-blown exec-raw query?

Upvotes: 2

Views: 272

Answers (1)

Daniel Compton
Daniel Compton

Reputation: 14559

Korma has a very helpful function korma.core/sql-only which will render the SQL string that would be executed.

(defentity calendars)
=> #'korma-test.core/calendars

(sql-only
  (select calendars
          (fields :x :y)
          (join :calendar_users (= :calendars.user_id :calendar_users.id))
          (join :meetings (= :calendars.id :meetings.id))
          (where (raw ["? ILIKE ANY(meetings.meeting_metadata)" "status_report"]))))
=> "SELECT \"calendars\".\"x\", \"calendars\".\"y\" FROM (\"calendars\" LEFT JOIN \"calendar_users\" ON \"calendars\".\"user_id\" = \"calendar_users\".\"id\") LEFT JOIN \"meetings\" ON \"calendars\".\"id\" = \"meetings\".\"id\" WHERE [\"? ILIKE ANY(meetings.meeting_metadata)\" \"status_report\"]"

or the more readable:

SELECT "calendars"."x",
       "calendars"."y"
FROM ("calendars"
      LEFT JOIN "calendar_users" ON "calendars"."user_id" = "calendar_users"."id")
LEFT JOIN "meetings" ON "calendars"."id" = "meetings"."id"
WHERE ["? ILIKE ANY(meetings.meeting_metadata)" "status_report"]

as you can see, the ILIKE is surrounded by []. Korma's raw just takes a raw string and doesn't support parameterisation like exec-raw does. The vector around the ILIKE string was just turned into a string with its contents. This is why you got a Postgres error about [.

You need to remove the [] from around the ILIKE string if you want to continue using raw, or see if exec-raw is going to fit your needs better. There is the very present danger of SQL injection if you are using 'raw' though which you will need to address.

;; require clojure.string :as str in your ns
;; change your clause from
(where (raw ["? ILIKE ANY(meetings.meeting_metadata)" "status_report"])))
;; to this
(where (raw (str/join " " ["'status_report'" "ILIKE ANY(meetings.meeting_metadata)"])))

Upvotes: 1

Related Questions