Pregunta

Tengo una función que comienza así:

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

Por supuesto, no me gusta esto en absoluto.Tengo este patrón que se repite en muchas áreas en mi base de código y me gustaría generalizar esto.

Entonces, se me ocurrió lo siguiente para comenzar:

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

Realmente hay algunas preguntas aquí:

- ¿Cómo puedo deconstruir la entrada de datos para que cree funciones X cuando X sea desconocida, es decir?que los valores de: uno es desconocido, y que se desconoce las cantidades de claves en la entrada de datos.

- Estoy pensando que este es un momento para crear una macro, pero nunca he construido uno antes, así que estoy dudando en la idea.

y para dar un pequeño contexto, las funciones deben devolver los valores para deconstruirse, pero creo que una vez que obtenga esta pieza resuelta, generalizar todo esto será factible:

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

¿Fue útil?

Solución

Algunas sugerencias:

  • def dentro de una función es realmente desagradable - Está alterando el entorno global, y puede causar todo tipo de problemas con la concurrencia.Sugeriría almacenar los resultados en un mapa en su lugar.
  • usted No necesita una macro aquí: todos los datos se pueden hacer con relativamente fácilmente dentro de una función

    , por lo tanto, sugeriría algo como:

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

    No probado ya que no tengo la configuración de su base de datos, ¡pero con suerte, eso le da una idea de cómo hacerlo sin macros ni globales mutables!

Otros consejos

bonita pregunta.En primer lugar, aquí está la macro que pidió:

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

Puede llamarlo así:

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

O si prefiere mantener todas sus configuraciones en un mapa, entonces aceptará cadena como el primer argumento en lugar de un símbolo:

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


Ahora, si no le importa que recomienda otra solución, probablemente eligió usar una sola función cerrada alrededor de la configuración.Algo así:

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

Por cierto, hay otra forma de usar 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)) 

Para obtener más información, recomiendo encarecidamente mirar a fuentes korma.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top