6

次のように始まる関数があります。

(defn data-one [suser]
    (def suser-first-name
       (select db/firstNames
            (fields :firstname)
            (where {:username suser})))
    (def suser-middle-name
        (select db/middleNames
            (fields :middlename)
            (where {:username suser})))
    (def suser-last-name
         (select db/middleNames
             (fields :lastname)
             (where {:username suser})))
    ;; And it just continues on and on...
        )

もちろん、私はこれがまったく好きではありません。コードベースの多くの領域でこのパターンが繰り返されており、これを一般化したいと思います。

それで、私は次のことを思いつきました:

(def data-input {:one '[suser-first-name db/firstNames :firstname] 
                      '[suser-middle-name db/middleNames :middlename]
                      '[suser-last-name db/lastNames :lastname]})

(defpartial data-build [data-item suser]
    ;; data-item takes the arg :one in this case
     `(def (data-input data-item)
        (select (data-input data-item)
            (fields (data-input data-item))
            (where {:username suser}))))

ここには本当にいくつかの質問があります:

-- x が不明な場合に x 関数を作成するようにデータ入力を分解するにはどうすればよいですか。:one の値が不明であり、data-input のキーの数が不明であること。

――そろそろマクロを作ろうかなと思っているのですが、作ったことがないので迷っています。

少し説明すると、関数は分解される値を返す必要がありますが、この問題が解決されれば、これらすべてを一般化することが可能になると思います。

(defpage "/page-one" []
    (let [suser (sesh/get :username)]       
    (data-one suser)
        [:p "Firat Name: " 
            [:i (let [[{fname :firstname}] suser-first-name]
                (format "%s" fname))]
        [:p "Middle Name: "  
            [:i (let [[{mname :emptype}] suser-middle-name]
                (format "%s" mname))]
        [:p "Last Name: " 
            [:i (let [[{lname :months}] suser-last-name]
                    (format "%s" lname))]]))
4

2 に答える 2

5

いくつかの提案:

  • def関数内は本当に厄介です-あなたは地球環境を変えています、そしてそれは並行性に関するあらゆる種類の問題を引き起こす可能性があります。代わりに、結果をマップに保存することをお勧めします。
  • ここではマクロは必要ありません。すべてのデータフェッチは、関数内で比較的簡単に実行できます。

したがって、私は次のようなものを提案します:

(def data-input [[:suser-first-name db/firstNames :firstname] 
                 [:suser-middle-name db/middleNames :middlename]
                 [:suser-last-name db/lastNames :lastname]])

(def data-build [data-input suser]
  (loop [output {}
         items (seq data-input)]
    (if items
      (recur
        (let [[kw db fieldname] (first items)]
          (assoc output kw (select db (fields fieldname) (where {:username suser})))) 
        (next items))
      output)))

データベースを設定していないため、テストされていませんが、マクロまたは可変グローバルを使用せずにこれを行う方法がわかるといいのですが。

于 2012-09-30T00:25:06.253 に答える
4

良い質問です。まず、あなたが求めたマクロは次のとおりです。

(defmacro defquery [fname table fields ]
  (let [arg-name (symbol 'user-name)
        fname (symbol fname)]
    `(defn ~fname [~arg-name]
       (print ~arg-name (str ~@ fields)))))

次のように呼び出すことができます。

(defquery suser-first-name db/firstNames [:firstname])

または、すべての構成をマップに保持したい場合は、シンボルの代わりに文字列を最初の引数として受け入れます。

(defquery "suser-first-name" db/firstNames [:firstname])

さて、私が別の解決策を推奨することを気にしないのであれば、おそらく、構成に閉じた単一の関数を使用することを選択したでしょう. そんな感じ:

(defn make-reader [query-configurations]
  (fn [query-type user-name]
    (let [{table :table field-names :fields} 
           (get query-configurations query-type)]
      (select table
             (apply fields field-names)
             (where {:username suser})))))

(def data-input {:firstname  {:table db/firstNames  :fields :firstname} 
                 :middlename {:table db/middleNames :fields :middlename}
                 :lastname   {:table db/lastNames   :fields :lastname}})

(def query-function (make-reader data-input))

;; Example of executing a query
(query-function :firstname "tom")

ところで、Korma を使用する別の方法があります。

;; This creates a template select from the table
(def table-select (select* db/firstNames))

;; This creates new select query for a specific field
(def first-name-select (fields table-select :firstname))

;; Creating yet another query that filters results by :username
(defn mkselect-for-user [suser query] 
  (where query {:username suser}))

;; Running the query for username "tom"
;; I fully specified exec function name only to show where it comes from.
(korma.core/exec (mkselect-for-user "tom" first-name-select)) 

詳細については、Korma のソースを参照することを強くお勧めします。

于 2012-09-30T00:05:09.147 に答える