2014-02-08 1 views
2

Некоторые сложные функции Postgres используют операторы, не входящие в стандарт SQL. Одним простым примером является набор операторов POSIX regular expression; Мне нужно, чтобы они включали выражение where where, которое использует границы слов.Использование нестандартных операторов postgres с SQL Korma

Предположим, что я хочу найти виджеты, которые входят в размер 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' 

Но становится очень трудно с Корме. Корма позволяет использовать 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)" 

осложняющим фактором является то, что другие условия динамически добавляются к карте где после этого один. Поэтому, даже если следующий пример работает, он не допускает строительство этой карты:

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

Таким образом, использует нестандартные операторы, такие как ~ выполнить этот матч возможного в Корме в сочетании с картой где? Как бы вы это сделали? Лучшие альтернативы или обходные пути?

+0

Я нашел [YeSQL] (https://github.com/krisajenkins/yesql) блестящим для подобных ситуаций. Он позволяет хранить ваши SQL-запросы, написанные на простом SQL, но обеспечивает действительно опрятный способ вызова их из Clojure. –

+0

Я должен буду помнить YeSQL; для этой стратегии существует много хороших вариантов использования. Тем не менее, похоже, что это не хорошо для динамически генерирующих запросов, что сделало бы его непригодным для этого варианта использования. –

ответ

1

Вы можете добавить дополнительные where пункты, из официальной документации (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)) 

Так что вы можете сделать что-то вроде этого:

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

EDIT: Еще один вариант

Вы можете создать свой собственный предикат:

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

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

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

Это одно решение, но теперь у меня есть вектор, где условия для броска вокруг, пока я не закончу построение запроса. Отслеживание статических условий и карты, которая по-прежнему будет динамически изменяться, будет сложной. –

+0

@BradKoch, справедливо. Я отредактировал и добавил еще один вариант (я только осушил код, поэтому я не совсем уверен, что Postgres его примет). – ponzao

+1

Ницца! Просто открыл это тоже. Если у вас возникла проблема, у korma есть некоторые недокументированные [функциональные возможности] (https://github.com/korma/Korma/blob/ce206b3/src/korma/sql/engine.clj#L215); не знаю, каковы были их намерения. Поддержка пользовательских предикатов более простым способом не должна быть слишком сложной. –

Смежные вопросы