Skip to content
Snippets Groups Projects
Commit a45b90bf authored by Wact B. Prot's avatar Wact B. Prot
Browse files

ini co

parents
No related branches found
No related tags found
No related merge requests found
# vl-data-insert
A Clojure library to insert vaclab style data in vaclab style database documents.
## Usage
```clojure
(def p "Calibration.Measurement.Values.Pressure")
(def m {:Type "a"
:Unit "b"
:Value [0]
:SdValue [0]
:N [1]})
(def d {:Calibration
{:Measurement
{:Values
{:Pressure
[{:Type "a"
:Unit "b"
:Value [0]
:SdValue [0]
:N [1]}]}}}})
(store-results d [m m m m] p)
;; =>
;; {:Calibration
;; {:Measurement
;; {:Values
;; {:Pressure
;; [{:Type "a",
;; :Unit "b",
;; :Value [0 0 0 0 0],
;; :SdValue [0 0 0 0 0],
;; :N [1 1 1 1 1]}]}}}}
```
## License
Copyright 2020 wactbprot
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
(defproject org.clojars.wactbprot/vl-data-insert "0.1.0"
:description "Functions to insert vaclab style data in vaclab style database documents."
:url "https://codeberg.org/wactbprot/vl-data-insert"
:license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
:url "https://www.eclipse.org/legal/epl-2.0/"}
:dependencies [[org.clojure/clojure "1.10.0"]]
:repl-options {:init-ns vl-data-insert.core})
(ns vl-data-insert.core
^{:author "wactbprot"
:doc "Inserts data into documents. This documents may be
calibration documents but also measurement docs."}
(:require [vl-data-insert.utils :as u]
[clojure.string :as string]))
;;------------------------------
;; data to doc
;;------------------------------
(defn vector-vals
"Ensures that the values of `:Value`,`:SdValue` and `:N` are
vectors."
[m]
(-> m
(u/vector-if :Value)
(u/vector-if :SdValue)
(u/vector-if :N)))
(defn append-and-replace
"Append `:Value`, `:SdValue` and `:N` if present. Relaces `:Type` and
`:Unit`."
[struct {t :Type v :Value u :Unit n :N s :SdValue}]
(->
(-> struct
(u/replace-if :Type t)
(u/replace-if :Unit u))
(u/append-if :Value v)
(u/append-if :SdValue s)
(u/append-if :N n)))
(defn fit-in-struct
"Fits `m` into the given structure `s`. Function looks up the
`:Type` of `m`. If a structure with the same `:Type` exist
[[append-and-replace]] is called."
[s m]
(if-let [t (:Type m)]
(let [same-type? (fn [x] (= (:Type x) t))
idx? (fn [i x] (when (same-type? x) i))]
(if-let [idx (first (keep-indexed idx? s))]
(assoc s idx (append-and-replace (nth s idx) m))
(conj s (vector-vals m))))))
(defn store-result
"Stores the result map `m` in the given `doc`ument under `p`ath. If
`m` contains `:Type` and `:Value` `m` is [[fit-in-struct]] and the
structure `s` is assumed to be a `vector`. Other cases (e.g. merge
in `:AuxValues`) are straight
forward (see [[vl-data-insert/test/cmp/doc_test.clj]] for details)."
[doc m p]
(let [v (u/path->kw-vec p)]
(if (and (:Type m) (:Value m))
(if-let [s (get-in doc v)]
(assoc-in doc v (fit-in-struct s m))
(assoc-in doc v [(vector-vals m)]))
(if-let [s (get-in doc v)]
(assoc-in doc v (merge s m))
(assoc-in doc v m)))))
(defn store-results
"Takes a vector of maps. Calls `store-result` on each map."
[doc res path]
(reduce
(fn [doc m] (store-result doc m path))
doc res))
(ns vl-data-insert.utils
^{:author "wactbprot"
:doc "Utils for data insert tasks."}
(:require [clojure.string :as string]))
(defn ensure-vec
"Ensures that `v` is a vector.
Example:
```clojure
(ensure-vec nil) ;!
;; nil
(ensure-vec 1)
;; [1]
(ensure-vec [1])
;; [1]
```"
[v]
(when v (if (vector? v) v [v])))
(defn vector-if
"Makes the value `v` behind the keyword `kw` a vector if `v` is not
nil."
[m kw]
(if (and (map? m) (keyword? kw))
(if-let [v (kw m)]
(assoc m kw (ensure-vec v))
m)))
(defn replace-if
"Replaces `v`alue of `k`ey in struct if `v`is not `nil`.
Example:
```clojure
(replace-if {:Type \"a\"} :Type \"b\")
;; {:Type \"b\"}
```
"
[m k v]
(if (and (some? v) (keyword? k)) (assoc m k v) m))
(defn append-if
"Appends `v` to the value of `k`. If `k` does not exist in `m`,
`k [v]` is assoced. If `k` does exist in `m`, `v` is conjed.
Example:
```clojure
(append-if {:Value [1 2 3]} :Value 4)
;; {:Value [1 2 3 4]}
```"
[m k v]
(if (and (some? v) (keyword? k))
(let [new-v (ensure-vec v)]
(if-let [old-v (k m)]
(assoc m k (into [] (concat old-v new-v)))
(assoc m k new-v)))
m))
(defn path->kw-vec
"Turns the path into a vector of keywords.
```clojure
(path->kw-vec \"a.b.c\")
;; [:a :b :c]
```"
[s]
{:pre [(string? s)]}
(into []
(map
keyword
(string/split s (re-pattern "\\.")))))
(ns vl-data-insert.core-test
(:require [clojure.test :refer :all]
[vl-data-insert.core :refer :all]))
(def m-vec {:Type "a" :Unit "a" :Value [0] :SdValue [0] :N [1]})
(def m-val {:Type "b" :Unit "b" :Value 1 :SdValue 1 :N 1})
(def m-vaa {:Type "a" :Unit "b" :Value 1 :SdValue 1 :N 1})
(deftest append-and-replace-test-i
(testing "append and replace (i)"
(is (= "b" (:Type (append-and-replace m-vec m-val)))
"Got the right type.")
(is (= "b" (:Unit (append-and-replace m-vec m-val)))
"Got the right unit.")
(is (= [0 1] (:Value (append-and-replace m-vec m-val)))
"Append the value.")
(is (= [0 1] (:SdValue (append-and-replace m-vec m-val)))
"Append the sdvalue.")
(is (= [1 1] (:N (append-and-replace m-vec m-val)))
"Append the n.")))
(deftest append-and-replace-test-ii
(testing "append and replace (ii)"
(is (= "a" (:Type (append-and-replace m-vec {})))
"Type remains unchanged.")
(is (= "a" (:Unit (append-and-replace m-vec {})))
"Unit remains unchanged.")
(is (= [0] (:Value (append-and-replace m-vec {})))
"Value remains unchanged.")
(is (= [0] (:SdValue (append-and-replace m-vec {})))
"Sdvalue remains unchanged.")
(is (= [1] (:N (append-and-replace m-vec {})))
"N remains unchanged.")))
(deftest append-and-replace-test-iii
(testing "append and replace (iii)"
(is (= "b" (:Type (append-and-replace {} m-val)))
"Type is inserted.")
(is (= "b" (:Unit (append-and-replace {} m-val)))
"Unit is inserted.")
(is (= [1] (:Value (append-and-replace {} m-val)))
"Value is inserted.")
(is (= [1] (:SdValue (append-and-replace {} m-val)))
"Sdvalue is inserted.")
(is (= [1] (:N (append-and-replace {} m-val)))
"N is inserted.")))
(def doc1 {:Calibration {:Measurement
{:Values
{:Pressure []}}}})
(def doc2 {:Calibration {:Measurement
{:Values
{:Pressure [{:Type "a"
:Unit "a"
:Value [0]
:SdValue [0]
:N [1]}]}}}})
(def doc2 {:Calibration
{:Measurement
{:Values
{:Pressure [
{:Type "a"
:Unit "b"
:Value [0]
:SdValue [0]
:N [1]}]}}}})
(def p1 "Calibration.Measurement.Values.Pressure")
(def p2 "Calibration.Measurement.Values.not-there")
(def p3 "Calibration.Measurement.AuxValues")
(def v1 [:Calibration :Measurement :Values :Pressure])
(def v2 [:Calibration :Measurement :Values :not-there])
(def v3 [:Calibration :Measurement :AuxValues])
(deftest store-result-i
(testing "results are stored (i)"
(is (= [m-vec] (get-in
(store-result doc1 m-vec p1)
v1))
"m-vec is inserted at path.")
(is (= [m-vec] (get-in
(store-result doc1 m-vec p2)
v2))
"m-vec is inserted if path is not present.")
(is (= [1] (:Value
(nth
(get-in
(store-result doc1 m-val p1)
v1)
0)))
"Value becomes a vector and is inserted at path.")
(is (= [1] (:Value
(nth
(get-in
(store-result doc1 m-val p2)
v2)
0)))
"Value becomes a vector and is inserted at non existing path.")
(is (= 2 (count
(get-in
(store-result doc2 m-val p1)
v1)))
"Map is added to existing path (Type differs).")
(is (= [0 1] (:Value
(nth
(get-in
(store-result doc2 m-vaa p1)
v1) 0)))
"Value is appended to existing path and structure (without vectors).")
(is (= "b" (:Unit
(nth
(get-in
(store-result doc2 m-vaa p1)
v1) 0)))
"Unit is updated at existing path and structure.")))
(deftest store-result-ii
(testing "results are stored plain (ii)"
(is (= {:OPK 1} (get-in
(store-result doc1 {:OPK 1} p3)
v3))
"Map is added.")
(is (= {:OPK 2} (get-in
(store-result
(store-result doc1 {:OPK 1} p3)
{:OPK 2} p3)
v3))
"Map is updated.")
(is (= {:OPK 1 :Gas "N2"} (get-in
(store-result
(store-result doc1 {:OPK 1} p3)
{:Gas "N2"} p3)
v3))
"Map is assoced.")))
(deftest store-results-i
(testing "results are stored(i)"
(is (= [0 1] (:Value
(nth
(get-in
(store-results doc1 [m-vec m-val m-vaa] p1)
v1)
0)))
"Values got attached if they have equal Types.")
(is (= [1] (:Value
(nth
(get-in
(store-results doc1 [m-vec m-val m-vaa] p1)
v1)
1)))
"Map is inserted and values become vectors.")))
(ns vl-data-insert.utils-test
(:require [clojure.test :refer :all]
[vl-data-insert.utils :refer :all]))
(def m-vec {:Type "a" :Unit "a" :Value [0] :SdValue [0] :N [1]})
(def m-val {:Type "b" :Unit "b" :Value 1 :SdValue 1 :N 1})
(deftest vector-if-i
(testing "makes vectors of vals (i)"
(is (= [0] (:Value (vector-if m-vec :Value)))
"Leaves [1] a vector.")
(is (= [1] (:Value (vector-if m-val :Value)))
"Makes 1 a vector.")
(is (nil? (:Value (vector-if nil :Value)))
"Don't crash on nil.")
(is (nil? (:Value (vector-if m-vec nil)))
"Don't crash on nil.")))
(def p1 "Calibration.Measurement.Values.Pressure")
(def v1 [:Calibration :Measurement :Values :Pressure])
(deftest path-to-keyword-i
(testing "Path translation (i)"
(is (= v1 (path->kw-vec p1))
"Translates path to keyword vector.")))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment