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