sql

Andrey Subbotin 2024-07-23T02:36:36.544079Z

Hi all, I seemingly have issues with transformations being not applied on aliased entities in korma selects.

Andrey Subbotin 2024-07-23T02:37:00.162639Z

(ns local.korma-lab
  (:require [korma.core :as k]))

(set! *warn-on-reflection* true)

(def dispatch-type
  {3 :email
   4 :other})
    
(k/defentity customer-actor-dispatch-process
  (k/transform #(update % :dispatch-type dispatch-type)))

;; This doesn't apply the transformation on the :dispatch-type field:

(k/select [customer-actor-dispatch-process :cadp]
          (k/where {:cadp.bill-id 13}))

;; => [{:bill-id 13,
;;      :dispatch-type 3,
;;      :id 13,
;;      ...}]

;; But this does...

(k/select customer-actor-dispatch-process
          (k/where {:customer-actor-dispatch-process.bill-id 13}))

;; => ({:bill-id 13,
;;      :dispatch-type :email,
;;      :id 13,
;;      ...})

(def query-bad (-> (k/select* [customer-actor-dispatch-process :cadp])
                   (k/where {:cadp.bill-id 13})))

;; => {:alias nil,
;;     :aliases #{},
;;     :db nil,
;;     :ent [{:db nil,
;;            :fields [],
;;            :name "customer-actor-dispatch-process",
;;            :pk :id,
;;            :prepares (#<Fn@246b4d80
;;                         local.korma_lab/make_transform[fn]>),
;;            :rel {},
;;            :table "customer-actor-dispatch-process",
;;            :transforms (#<Fn@5d6a236d
;;                           local.korma_lab/make_transform[fn]>)} :cadp],
;;     :fields [:korma.core/*],
;;     :from
;;       [[{:db nil,
;;          :fields [],
;;          :name "customer-actor-dispatch-process",
;;          :pk :id,
;;          :prepares (#<Fn@246b4d80 local.korma_lab/make_transform[fn]>),
;;          :rel {},
;;          :table "customer-actor-dispatch-process",
;;          :transforms (#<Fn@5d6a236d
;;                         local.korma_lab/make_transform[fn]>)} :cadp]],
;;     :group [],
;;     :joins [],
;;     :modifiers [],
;;     :options nil,
;;     :order [],
;;     :results :results,
;;     :table nil,
;;     :type :select,
;;     :where
;;       [{:korma.sql.utils/args
;;           [" AND "
;;            ({:korma.sql.utils/args [:cadp.bill-id "=" 13],
;;              :korma.sql.utils/pred
;;                #<Fn@60784dcb korma.sql.engine/do_infix>})],
;;         :korma.sql.utils/pred
;;           #<Fn@6028c840 korma.sql.engine/do_group>}]}

(k/exec query-bad)

;; => [{:bill-id 13,
;;      :dispatch-type 3,
;;      :id 13,
;;      ...}]

(def query-good (-> (k/select* customer-actor-dispatch-process)
                    (k/where {:customer-actor-dispatch-process.bill-id 13})))
;; => {:alias nil,
;;     :aliases #{},
;;     :db nil,
;;     :ent {:db nil,
;;           :fields [],
;;           :name "customer-actor-dispatch-process",
;;           :pk :id,
;;           :prepares (#<Fn@246b4d80
;;                        local.korma_lab/make_transform[fn]>),
;;           :rel {},
;;           :table "customer-actor-dispatch-process",
;;           :transforms (#<Fn@5d6a236d
;;                          local.korma_lab/make_transform[fn]>)},
;;     :fields [:korma.core/*],
;;     :from [{:db nil,
;;             :fields [],
;;             :name "customer-actor-dispatch-process",
;;             :pk :id,
;;             :prepares (#<Fn@246b4d80
;;                          local.korma_lab/make_transform[fn]>),
;;             :rel {},
;;             :table "customer-actor-dispatch-process",
;;             :transforms (#<Fn@5d6a236d
;;                            local.korma_lab/make_transform[fn]>)}],
;;     :group [],
;;     :joins [],
;;     :modifiers [],
;;     :options nil,
;;     :order [],
;;     :results :results,
;;     :table "customer-actor-dispatch-process",
;;     :type :select,
;;     :where
;;       [{:korma.sql.utils/args
;;           [" AND "
;;            ({:korma.sql.utils/args
;;                [{:korma.sql.utils/generated
;;                    "customer_actor_dispatch_process.bill_id"} "=" 13],
;;              :korma.sql.utils/pred
;;                #<Fn@60784dcb korma.sql.engine/do_infix>})],
;;         :korma.sql.utils/pred
;;           #<Fn@6028c840 korma.sql.engine/do_group>}]}

(k/exec query-good)

;; => ({:bill-id 13,
;;      :dispatch-type :email,
;;      :id 13,
;;      ...})

;; The below is how exec and apply-transforms are defined in korma.core:

; (defn- apply-transforms
;   [query results]
;   (if (= (:type query) :delete)
;     results
;     (if-let [trans (-> query :ent :transforms seq)] ;; <-- Please note this expects :transforms to be found directly on :ent
;       (let [trans-fn (apply comp trans)]
;         (if (sequential? results)
;           (map trans-fn results)
;           (trans-fn results)))
;       results)))

; (defn exec
;   "Execute a query map and return the results."
;   [query]
;   (let [query  (apply-prepares query)
;         query  (bind-query query (eng/->sql query))
;         sql    (:sql-str query)
;         params (:params query)]
;     (cond
;       (:sql query)             sql
;       (= *exec-mode* :sql)     sql
;       (= *exec-mode* :query)   query
;       (= *exec-mode* :dry-run) (do
;                                  (println "dry run ::" sql "::" (vec params))
;                                  (let [result-keys (conj (->> query :ent :rel vals
;                                                                               (map deref)
;                                                                               (filter (comp #{:belongs-to} :rel-type))
;                                                                               (map :fk-key))
;                                                          (-> query :ent :pk))
;                                        results     (apply-posts query [(zipmap result-keys (repeat 1))])]
;                                    (first results)
;                                    results))
;       :else                    (let [results (db/do-query query)]
;                                  (apply-transforms query (apply-posts query results))))))

;; The issue stems from how the transforms are retrieved in the
;; apply-transforms function:

;; 1. In query-bad, the :ent key contains a vector [{...} :cadp] instead
;; of just the entity map. This is due to the aliasing syntax
;; [customer-actor-dispatch-process :cadp] used in k/select*.

;; 2. In query-good, the :ent key directly contains the entity map, which
;; includes the :transforms key.

;; 3. The apply-transforms function tries to access :transforms directly
;; from :ent, which works for query-good but not for query-bad.

Andrey Subbotin 2024-07-23T02:39:47.486909Z

This is for korma v0.3.3 which I understand is an old one, but the apply-transforms seems to be the same in newer versions anyway. I mainly wonder if supplying aliases on tables in the query with a vector like [entity :alias] is a supported way of doing things at all? The select query seems to be generated fine, but the transforms do not run. Is there a more proper way to use aliases so that one doesn’t have to supply the full-blown entity/table name in every where clause and field selectors?

p-himik 2024-07-23T02:44:38.508369Z

Seems like it's this issue? https://github.com/korma/Korma/issues/96 Looks like Korma is properly abandoned...

2024-07-23T02:54:05.590159Z

Maybe check out https://github.com/seancorfield/honeysql

Andrey Subbotin 2024-07-23T04:41:57.142249Z

Heh, that sucks. Moving to honeysql or something else would be a solution in the long run, but not something we can do at the moment, as there’s quite a bunch of korma-based code in the project. 😟

Andrey Subbotin 2024-07-23T04:43:08.244249Z

Thanks for looking into this anyway 🙂