Question

J'ai une fonction qui commence comme ceci:

(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...
        )

Bien sûr, je n'aime pas tout cela du tout.J'ai ce modèle en train de répéter dans de nombreuses régions de ma base de code et j'aimerais généraliser ceci.

Alors, je suis venu avec ce qui suit pour commencer:

(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}))))

Il y a vraiment quelques questions ici:

- Comment puis-je déconstruire l'entrée de données afin qu'elle crée des fonctions x lorsque x est inconnu, c'est-à-dire.que les valeurs de: une est inconnue et que les quantités de clés dans l'entrée de données sont inconnues.

- Je pense que c'est un moment de créer une macro, mais je n'ai jamais construit un avant, alors je suis hésitant à l'idée.

et pour donner un peu de contexte, les fonctions doivent renvoyer des valeurs à déconstruire, mais je pense qu'une fois que j'obtiens cette pièce résolue, généralisant tout cela sera faisable:

(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))]]))

Était-ce utile?

La solution

Quelques suggestions:

  • def à l'intérieur d'une fonction est vraiment méchant - vous modifiez l'environnement global et peut causer toutes sortes de problèmes avec la concurrence.Je suggérerais de stocker les résultats dans une carte à la place.
  • vous Vous n'avez pas besoin d'une macro ici - toutes les récupérations de données peuvent être effectuées relativement facilement dans une fonction

    Je suggérerais donc quelque chose comme:

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

    Non testé car je n'ai pas votre configuration de base de données - mais j'espère que cela vous donne une idée de la façon de faire cela sans macros ni globaux mutables!

Autres conseils

Nice question.Tout d'abord voici la macro que vous avez demandée:

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

Vous pouvez l'appeler comme ça:

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

ou si vous préférez garder toutes vos configurations sur une carte, elle acceptera la chaîne comme premier argument au lieu d'un symbole:

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


Maintenant, si cela ne vous dérange pas que je recommande une autre solution, j'aurais probablement choisi d'utiliser une seule fonction fermée autour de la configuration.Quelque chose comme ça:

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

Au fait, il y a une autre façon d'utiliser 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)) 

Pour plus d'informations, je vous recommande vivement de regarder sources de Korma.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top