-
Notifications
You must be signed in to change notification settings - Fork 4
/
values.cljc
59 lines (52 loc) · 1.77 KB
/
values.cljc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
(ns com.yetanalytics.flint.spec.values
(:require [clojure.spec.alpha :as s]
[com.yetanalytics.flint.spec.axiom :as ax]))
(def value-spec
(s/or :ax/iri ax/iri?
:ax/prefix-iri ax/prefix-iri?
:ax/num-lit number?
:ax/bool-lit boolean?
:ax/str-lit ax/valid-string?
:ax/lmap-lit ax/lang-map?
:values/undef nil?))
(defn- matching-val-lengths*
[m]
(let [vars (first (keys m))
values (first (vals m))
nv (count vars)]
(every? #(= nv (count %)) values)))
(defn- matching-val-lengths
[m]
(let [values (vals m)
nv (count (first values))]
(every? #(= nv (count %)) values)))
(defn- clojure->sparql
[m]
(let [mfn (fn [& ks] (vec ks))
vars (->> m keys vec)
values (->> m vals (apply map mfn) vec)]
{vars values}))
;; For some reason `s/map-of` doesn't conform the keys properly
;; so we have to do it manually.
(defn- conform-vars
[m]
(let [k (first (keys m))
v (first (vals m))]
[(mapv (fn [vr] [:ax/var vr]) k) v]))
(def values-clause-spec
(s/and
(s/or :values/sparql-format
(s/and (s/map-of any? any? :min-count 1 :max-count 1)
(s/map-of (s/coll-of ax/variable?)
(s/coll-of (s/coll-of value-spec)))
matching-val-lengths*
(s/conformer conform-vars))
:values/clojure-format
(s/and (s/map-of any? any? :min-count 1)
(s/map-of ax/variable? (s/coll-of value-spec))
matching-val-lengths
(s/conformer clojure->sparql)
(s/conformer conform-vars)))
(s/conformer second)))
;; single-branch `s/or` is used to conform values
(s/def ::values (s/or :values/map values-clause-spec))