Skip to content

Instantly share code, notes, and snippets.

@x
Last active August 9, 2016 07:40
Show Gist options
  • Save x/cb4580dc23e08b7cb98ff0139a340278 to your computer and use it in GitHub Desktop.
Save x/cb4580dc23e08b7cb98ff0139a340278 to your computer and use it in GitHub Desktop.
(require '[clojure.string :refer [join]])
(defprotocol ExpressionBuilderProtocol
(ensureExprAttrName [this val])
(ensureExprAttrVal [this val])
(ADD [this attr amnt])
(SET [this attr val])
(toArgs [this]))
(defrecord ExpressionBuilder
[expr-map expr-attr-vals expr-attr-names]
ExpressionBuilderProtocol
(ensureExprAttrName [this attr]
(if (get expr-attr-names attr)
expr-attr-names
(assoc expr-attr-names
attr
(str "#attr" (count expr-attr-names)))))
(ensureExprAttrVal [this val]
(if (get expr-attr-vals val)
expr-attr-vals
(assoc expr-attr-vals
val
(str ":val" (count expr-attr-vals)))))
(ADD [this attr amnt]
(let [expr-attr-names (.ensureExprAttrName this attr)
expr-attr-vals (.ensureExprAttrVal this amnt)
attr (get expr-attr-names attr)
amnt (get expr-attr-vals amnt)
add-expr (format "%s = %s + %s" attr attr amnt)
expr-map (update expr-map ::ADD (fnil conj []) add-expr)]
(ExpressionBuilder. expr-map expr-attr-vals expr-attr-names)))
(SET [this attr val]
(let [expr-attr-names (.ensureExprAttrName this attr)
expr-attr-vals (.ensureExprAttrVal this val)
attr (get expr-attr-names attr)
val (get expr-attr-vals val)
add-expr (format "%s = %s" attr val)
expr-map (update expr-map ::SET (fnil conj #{}) add-expr)]
(ExpressionBuilder. expr-map expr-attr-vals expr-attr-names)))
(toArgs
[{:keys [expr-attr-vals expr-attr-names expr-map]}]
{:expr-attr-vals (clojure.set/map-invert expr-attr-vals)
:expr-attr-names (clojure.set/map-invert expr-attr-names)
:expr (join " " (map (fn [[k exprs]] (str (name k) " " (join "," exprs)))
expr-map))}))
(defn table-fn
[_]
"table_foo")
(defn part-key-fn
[{:keys [host hour]}]
(str host "::" hour))
(defn sort-key-fn
[{:keys [source_path target_path]}]
(str source_path "::" target_path))
(->>
[{:host "h1"
:source_path "sp1"
:target_path "tp1"
:hour 7
:minute 10
:weight 100}
{:host "h2"
:source_path "sp2"
:target_path "tp2"
:hour 7
:minute 10
:weight 100}
{:host "h1"
:source_path "sp1"
:target_path "tp1"
:hour 7
:minute 10
:weight 200}
{:host "h1"
:source_path "sp1"
:target_path "tp1"
:hour 7
:minute 11
:weight 100}]
(reduce (fn [exprs click]
(update exprs
((juxt table-fn part-key-fn sort-key-fn) click)
#(-> (or % (ExpressionBuilder. {} {} {}))
(.ADD (str "M" (:minute click)) (:weight click))
(.SET "SourcePath" (:source_path click))
(.SET "TargetPath" (:target_path click)))))
{})
(map (fn [[[table-name part-key sort-key] expr]]
(println "apply update to "
(merge {:table-name table-name
:part-key part-key
:sort-key sort-key}
(.toArgs expr))))))
;=> apply update to {:table-name table_foo, :part-key h1::7, :sort-key sp1::tp1, :expr-attr-vals {:val0 100, :val1 sp1, :val2 tp1, :val3 200}, :expr-attr-names {#attr0 M10, #attr1 SourcePath, #attr2 TargetPath, #attr3 M11}, :expr ADD #attr0 = #attr0 + :val0,#attr0 = #attr0 + :val3,#attr3 = #attr3 + :val0 SET #attr1 = :val1,#attr2 = :val2}
;=> apply update to {:table-name table_foo, :part-key h2::7, :sort-key sp2::tp2, :expr-attr-vals {:val0 100, :val1 sp2, :val2 tp2}, :expr-attr-names {#attr0 M10, #attr1 SourcePath, #attr2 TargetPath}, :expr ADD #attr0 = #attr0 + :val0 SET #attr1 = :val1,#attr2 = :val2}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment