Question

Some complex features of Postgres utilize operators that are not part of the SQL standard. One simple example is the set of POSIX regular expression operators; I need them to include a where clause expression that utilizes word boundaries.

Let's say that I want to find widgets that come in size 1, where size is a string containing a json encoded list of integers.

Sample data:

ID  Size
1   "[1]"
2   "[1,2,4,12]"
3   "[4,12]"
4   "[2,4]"

This is trivial with raw SQL:

SELECT * FROM widgets WHERE size ~ '\m1\M'

But gets very difficult with korma. Korma does allow the use of predicates in the where map, but the functionality is very restrictive. Some things that don't work:

=> (select "widgets" (where {:size ["~" "\\m1\\M"]}))
ClassCastException java.lang.String cannot be cast to clojure.lang.IFn korma.sql.engine/pred-vec (engine.clj:218)

=> (select "widgets" (where {:size [(raw "~") "\\m1\\M"]}))
Failure to execute query with SQL:
SELECT "widgets".* FROM "widgets" WHERE (?)  ::  [\m1\M]

=> (select "widgets" (where {:size (raw "~ '\\m1\\M'")}))
Failure to execute query with SQL:
SELECT "widgets".* FROM "widgets" WHERE ("widgets"."size" = ~ '\m1\M')  ::  []

=> (sql-only (select "widgets" (where {:size [(raw "~ '\\m1\\M'")]})))
"SELECT \"widgets\".* FROM \"widgets\" WHERE (NULL)"

A complicating factor is that other conditions are dynamically added to the where map after this one. So even though the following example works, it doesn't allow for construction of that map:

=> (sql-only (select "widgets" (where (raw "size ~ '\\m1\\M'"))))
"SELECT \"widgets\".* FROM \"widgets\" WHERE size ~ '\\m1\\M'"

So, is using non standard operators like ~ to perform this match possible in korma in conjunction with a where map? How would you do it? Best alternatives or workarounds?

Was it helpful?

Solution

You can add additional where clauses, from the official documentation (http://sqlkorma.com/docs#select):

;; Multiple where's are joined with AND, so this
;; is also the same:
(-> (select* users)
    (where {:first "john"})
    (where {:last "doe"})
    (as-sql))

So you can do something like this:

(sql-only (select "widgets"
            (where (raw "size ~ '\\m1\\M'"))
            (where {:.. "?"})))

EDIT: Another option

You could create your own custom predicate:

(require '[korma.sql.engine :refer [infix]])

(defn tilde
  [k v]
  (infix k "~" v))

(sql-only
  (select "widgets"
    (where {:size [tilde "\\m1\\M"]
            :... [like "..."]})))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top