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 {t :Type v :Value u :Unit n :N s :SdValue}]
024    (->
025     (-> struct
026         (u/replace-if :Type t)
027         (u/replace-if :Unit u))
028     (u/append-if :Value v)
029     (u/append-if :SdValue s)
030     (u/append-if :N n)))
031  
032  (defn fit-in-struct
033    "Fits `m` into the given structure `s`. Function looks up the
034    `:Type` of `m`. If a structure with the same `:Type` exist
035    [[append-and-replace]] is called."
036    [s m]
037    (if-let [t (:Type m)]
038      (let [same-type? (fn [x] (= (:Type x) t))
039            idx?       (fn [i x] (when (same-type? x) i))]
040        (if-let [idx (first (keep-indexed idx? s))]
041          (assoc s idx (append-and-replace (nth s idx) m))
042          (conj s (vector-vals m))))))
043  
044  (defn store-result
045    "Stores the result map `m` in the given `doc`ument under `p`ath. If
046    `m` contains `:Type` and `:Value` `m` is [[fit-in-struct]] and the
047    structure `s` is assumed to be a `vector`. Other cases (e.g. merge
048    in `:AuxValues`) are straight
049    forward (see [[vl-data-insert/test/cmp/doc_test.clj]] for details)."
050    [doc m p]
051    (let [v (u/path->kw-vec p)]
052      (if (and (:Type m) (:Value m))
053        (if-let [s (get-in doc v)]
054          (assoc-in doc v (fit-in-struct s m))
055          (assoc-in doc v [(vector-vals m)]))
056        (if-let [s (get-in doc v)]
057          (assoc-in doc v (merge s m))
058          (assoc-in doc v m)))))
059  
060  (defn store-results
061    "Takes a vector of maps. Calls `store-result` on each map.
062  
063    Example:
064    ```clojure
065    (def p \"Calibration.Measurement.Values.Pressure\")
066    (def m {:Type    \"a\"
067          :Unit    \"b\"
068          :Value   [0]
069          :SdValue [0]
070          :N       [1]})
071    
072    (def d {:Calibration
073           {:Measurement
074            {:Values
075             {:Pressure
076             [{:Type    \"a\"
077              :Unit    \"b\"
078              :Value   [0]
079              :SdValue [0]
080              :N       [1]}]}}}})
081    
082    (store-results d [m m m m] p)
083  
084    ;; =>
085    ;;   {:Calibration
086    ;;    {:Measurement
087    ;;     {:Values
088    ;;      {:Pressure
089    ;;       [{:Type \"a\",
090    ;;         :Unit \"b\",
091    ;;         :Value [0 0 0 0 0],
092    ;;         :SdValue [0 0 0 0 0],
093    ;;         :N [1 1 1 1 1]}]}}}}
094    ```
095  
096    "
097    [doc v p]
098    (reduce (fn [doc m] (store-result doc m p)) doc v))