使用SQL Korma的非标准postgres运算符

时间:2014-02-08 22:26:21

标签: postgresql clojure sqlkorma

Postgres的一些复杂功能使用不属于SQL标准的运算符。一个简单的例子是POSIX regular expression运算符集;我需要它们包含一个利用单词边界的where子句表达式。

假设我想找到大小为1的小部件,其中size是一个包含json编码的整数列表的字符串。

示例数据:

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

这对于原始SQL来说是微不足道的:

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

但与korma相比变得非常困难。 Korma允许在where map中使用predicates,但功能非常严格。有些事情不起作用:

=> (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)"

一个复杂因素是其他条件会在此之后动态添加到where map。因此,即使以下示例有效,也不允许构建该映射:

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

那么,是否正在使用像~这样的非标准运算符来在korma中与where map一起执行此匹配?你会怎么做?最佳替代方案或解决方法?

1 个答案:

答案 0 :(得分:1)

您可以在官方文档(http://sqlkorma.com/docs#select)中添加其他where子句:

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

所以你可以这样做:

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

编辑:另一种选择

您可以创建自己的自定义谓词:

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

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

(sql-only
  (select "widgets"
    (where {:size [tilde "\\m1\\M"]
            :... [like "..."]})))