001  (ns vl-data-insert.core
002    ^{:author "wactbprot"
003      :doc "Inserts data into documents.  This documents may be
004            calibration documents but also measurement docs."}
005    (:require [vl-data-insert.utils :as u]
006              [clojure.string :as string]))
007  
008  ;;------------------------------
009  ;; data to doc
010  ;;------------------------------
011  (defn vector-vals
012    "Ensures that the values of `:Value`,`:SdValue` and `:N` are
013    vectors."
014    [m]
015    (-> m
016        (u/vector-if :Value)
017        (u/vector-if :SdValue)
018        (u/vector-if :N)))
019  
020  (defn append-and-replace
021    "Append `:Value`, `:SdValue` and `:N` if present. Relaces `:Type` and
022    `:Unit`."
023    [struct m]
024    (let [{t :Type v :Value u :Unit n :N s :SdValue} m]
025      (->
026       (-> struct
027           (u/replace-if (u/check-kw m :Type) t)
028         (u/replace-if (u/check-kw m :Unit) u))
029       (u/append-if (u/check-kw m :Value) v)
030       (u/append-if (u/check-kw m :SdValue) s)
031       (u/append-if (u/check-kw m :N) n))))
032  
033  (defn fit-in-struct
034    "Fits `m` into the given structure `s`. Function looks up the
035    `:Type` of `m`. If a structure with the same `:Type` exist
036    [[append-and-replace]] is called."
037    [s m]
038    (if-let [t (:Type m)]
039      (let [same-type? (fn [x] (= (:Type x) t))
040            idx?       (fn [i x] (when (same-type? x) i))]
041        (if-let [idx (first (keep-indexed idx? s))]
042          (assoc s idx (append-and-replace (nth s idx) m))
043          (conj s (vector-vals m))))))
044  
045  (defn store-result
046    "Stores the result `x`(ensured to be a map `m`) in the given
047    `d`ocument under `p`ath. If `m` contains `:Type` and `:Value` `m`
048    is [[fit-in-struct]] and the structure `s` is assumed to be a
049    `vector`. Other cases (e.g. merge in `:AuxValues`) are straight
050    forward (see [[vl-data-insert/test/cmp/doc_test.clj]] for details)."
051    [d x p]
052    (let [[m v] (u/ensure-map x (u/path->kw-vec p))]
053      (if (and (contains? m :Type) (contains? m :Value))
054        (if-let [s (get-in d v)]
055          (assoc-in d v (fit-in-struct s m))
056          (assoc-in d v [(vector-vals m)]))
057        (if-let [s (get-in d v)]
058          (assoc-in d v (merge s m))
059          (assoc-in d v m)))))
060  
061  (defn store-results
062    "Takes a vector of maps. Calls `store-result` on each map.
063  
064    Example:
065    ```clojure
066    (def p \"Calibration.Measurement.Values.Pressure\")
067    (def m {:Type    \"a\"
068          :Unit    \"b\"
069          :Value   [0]
070          :SdValue [0]
071          :N       [1]})
072    
073    (def d {:Calibration
074           {:Measurement
075            {:Values
076             {:Pressure
077             [{:Type    \"a\"
078              :Unit    \"b\"
079              :Value   [0]
080              :SdValue [0]
081              :N       [1]}]}}}})
082    
083    (store-results d [m m m m] p)
084  
085    ;; =>
086    ;;   {:Calibration
087    ;;    {:Measurement
088    ;;     {:Values
089    ;;      {:Pressure
090    ;;       [{:Type \"a\",
091    ;;         :Unit \"b\",
092    ;;         :Value [0 0 0 0 0],
093    ;;         :SdValue [0 0 0 0 0],
094    ;;         :N [1 1 1 1 1]}]}}}}
095    ```"
096    [doc v p]
097    (reduce (fn [doc m] (store-result doc m p)) doc v))