2

Clojure+Kormaを使用して単純なクエリを実行してレコード数を抽出しようとしています。これが私がやろうとしていることです:

(defmacro number-of [ref & filter]
  `(let [basetmp# (-> (kc/select* ~ref)
                      (kc/aggregate (count :*) :cnt))]
     (if ~filter
       (-> basetmp#
           (kc/where ~filter))
       basetmp#)))

ただし、このマクロを使用しようとすると、次のエラーメッセージが表示されます。渡された引数の数(2)が間違っています:core $ count

関数で実行するとクエリは完全に機能しますが、マクロに何か問題があるか、見つからないことがあります:(

ありがとう、ニコ

4

1 に答える 1

4

ポンザオが指摘したように、間違ったカウントを拾っています。

マクロ展開を見ると

(number-of 'foo)  ;; expands to....

(clojure.core/let [basetmp__9167__auto__ (clojure.core/->
                                          (korma.core/select* 'foo)
                                          (korma.core/aggregate
                                            (clojure.core/count :*)
                                            :cnt))]
  (if nil
    (clojure.core/-> basetmp__9167__auto__ (korma.core/where nil))
    basetmp__9167__auto__))    

したがって、マクロのカウントが として展開されるのを防ぐ必要がありますclojure.core/count。これは、unquote/quote を使用して次のように行うことができます。

(defmacro number-of [ref & filter]
  `(let [basetmp# (-> (kc/select* ~ref)
                      (kc/aggregate (~'count :*) :cnt))]
     (if ~filter
       (-> basetmp#
           (kc/where ~filter))
       basetmp#)))

その後、期待どおりに展開します...

(clojure.core/let [basetmp__9137__auto__ (clojure.core/->
                                          (korma.core/select* 'foo)
                                          (korma.core/aggregate
                                            (count :*)
                                            :cnt))]
  (if nil
    (clojure.core/-> basetmp__9137__auto__ (korma.core/where nil))
    basetmp__9137__auto__))

結果の SQL は妥当に見えます。

(kc/as-sql (number-of 'foo))
"SELECT COUNT(*) \"cnt\" FROM \"foo\""

更新:
「カウントは実際に何を表しているのですか?」というコメントから - これkc/aggregateもマクロであり、引数が一種の「SQL 集約」DSL であることがわかっている場合は、kc/aggregate呼び出しも拡張できます。engine.cljに、最終的にマップされるparse-aggregate関数 があることがわかります。korma.sql.fn/agg-count

(clojure.core/let [q__2640__auto__ (kc/select* 'foo)]
  (korma.sql.engine/bind-query
    q__2640__auto__
    (clojure.core/let [res__2641__auto__ (korma.core/fields
                                           q__2640__auto__
                                           [(clojure.core/->
                                             q__2640__auto__
                                             (korma.sql.fns/agg-count
                                               :*))
                                            :cnt])]
      (if nil
        (korma.core/group res__2641__auto__ nil)
        res__2641__auto__))))
于 2013-03-11T00:50:46.597 に答える