collugure : 매크로의 시간을지도에서 동적으로 만듭니다.
-
11-12-2019 - |
문제
다음과 같이 시작하는 기능이 있습니다.
(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가 알 수 없을 때 X 함수를 생성하도록 데이터 입력을 어떻게 해체 할 수 있습니까?하나의 값은 알려지지 않았으며 데이터 입력의 키의 수량이 알려지지 않았 음을 알 수 없습니다.
- 나는 이것이 매크로를 만드는 데 시간이지만, 나는 전에 결코 건설 한 적이 없기 때문에, 나는 그 아이디어에 대해 주저하고있다.
조금 맥락을주기 위해 기능은 해체 될 값을 반환해야하지만이 작품을 해결하면이 작품을 해결하면이 모든 것을 일반화 할 수 있습니다 :
(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))]]))
. 해결책
몇 가지 제안 :
-
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)))
데이터베이스 설정이 없으므로 테스트하지는 않지만 매크로 또는 변경할 수없는 전역 없이이 작업을 수행하는 방법에 대한 아이디어를 제공합니다!
다른 팁
좋은 질문.우선 여기에 당신이 요구 한 매크로가 있습니다 :
(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 소스를 보는 것이 좋습니다..