diff --git a/dev-resources/test-fixtures/inputs/query/select/select-14.edn b/dev-resources/test-fixtures/inputs/query/select/select-14.edn index 21227d2..95dfc62 100644 --- a/dev-resources/test-fixtures/inputs/query/select/select-14.edn +++ b/dev-resources/test-fixtures/inputs/query/select/select-14.edn @@ -1,4 +1,5 @@ ;; SELECT with both lists and blank node vectors {:prefixes {:$ ""} :select [?x] - :where [{(1 [:p :q] (2 ?x)) {}}]} + :where [{(1 [:p :q] (2 ?x)) {} + () {:r #{[]}}}]} diff --git a/dev-resources/test-fixtures/outputs/query/select/select-14.rq b/dev-resources/test-fixtures/outputs/query/select/select-14.rq index 2f7ded6..ea4e806 100644 --- a/dev-resources/test-fixtures/outputs/query/select/select-14.rq +++ b/dev-resources/test-fixtures/outputs/query/select/select-14.rq @@ -2,4 +2,5 @@ PREFIX : SELECT ?x WHERE { ( 1 [ :p :q ] ( 2 ?x ) ) . + () :r [] . } diff --git a/src/main/com/yetanalytics/flint/format/triple.cljc b/src/main/com/yetanalytics/flint/format/triple.cljc index be7aa6d..3b3f99a 100644 --- a/src/main/com/yetanalytics/flint/format/triple.cljc +++ b/src/main/com/yetanalytics/flint/format/triple.cljc @@ -25,24 +25,22 @@ (defmethod f/format-ast-node :triple.vec/s [_ [_ [s-str]]] (str s-str " .")) +(defn- format-spo-pretty [s-str po-str] + (let [indent (->> (repeat (inc (count s-str)) " ") + (cstr/join "") + (str "\n"))] + (str s-str " " (cstr/replace po-str #"\n" indent)))) + +(defn- format-spo [s-str po-str] + (str s-str " " po-str)) + (defmethod f/format-ast-node :triple.nform/spo [{:keys [pretty?]} [_ spo-pairs]] - (if pretty? + (let [format-spo (if pretty? format-spo-pretty format-spo) + join-sep (if pretty? " .\n" " . ")] (str (->> spo-pairs (map (fn [[s-str po-str]] - (let [indent (->> (repeat (inc (count s-str)) " ") - (cstr/join "") - (str "\n"))] - (str s-str " " (cstr/replace po-str #"\n" indent))))) - (cstr/join " .\n")) - " .") - (str (->> spo-pairs - (map (fn [[s-str po-str]] (str s-str " " po-str))) - (cstr/join " . ")) - " ."))) - -(defmethod f/format-ast-node :triple.nform/s [{:keys [pretty?]} [_ s-pairs]] - (let [join-sep (if pretty? " .\n" " . ")] - (str (->> s-pairs (map (fn [[s-str _]] s-str)) (cstr/join join-sep)) + (if (empty? po-str) s-str (format-spo s-str po-str)))) + (cstr/join join-sep)) " ."))) (defmethod f/format-ast-node :triple.nform/po [{:keys [pretty?]} [_ po-strs]] @@ -51,6 +49,9 @@ (map (fn [[p o]] (str p " " o))) (cstr/join join-sep)))) +(defmethod f/format-ast-node :triple.nform/po-empty [_ _] + "") + (defmethod f/format-ast-node :triple.nform/o [_ [_ o-strs]] (->> o-strs (cstr/join " , "))) diff --git a/src/main/com/yetanalytics/flint/spec/triple.cljc b/src/main/com/yetanalytics/flint/spec/triple.cljc index 0df4a77..41cc089 100644 --- a/src/main/com/yetanalytics/flint/spec/triple.cljc +++ b/src/main/com/yetanalytics/flint/spec/triple.cljc @@ -197,11 +197,9 @@ ;; Predicate Object #?(:clj - (defmacro make-pred-objs-spec - [pred-spec objs-spec] + (defmacro make-pred-objs-spec [pred-spec objs-spec] `(s/map-of ~pred-spec (s/or :triple.nform/o ~objs-spec) - :into [] - :min-count 1))) + :min-count 1 :conform-keys true :into []))) (def pred-objs-spec (make-pred-objs-spec ::predicate obj-set-spec)) @@ -220,10 +218,24 @@ ;; Subject Predicate Object +(def empty-map-spec + (s/map-of any? any? :count 0 :conform-keys true :into [])) + +#?(:clj + (defn- valid-conformed-spo? [spo-pairs] + (every? + (fn [[s po]] + (or (#{:triple/list :triple/bnodes} (first s)) + (#{:triple.nform/po} (first po)))) + spo-pairs))) + #?(:clj (defmacro make-nform-spec [subj-spec pred-objs-spec] - `(s/map-of ~subj-spec (s/or :triple.nform/po ~pred-objs-spec) - :conform-keys true :into []))) + `(s/and (s/map-of ~subj-spec + (s/or :triple.nform/po ~pred-objs-spec + :triple.nform/po-empty empty-map-spec) + :conform-keys true :into []) + valid-conformed-spo?))) (def normal-form-spec (make-nform-spec ::subject pred-objs-spec)) @@ -240,25 +252,6 @@ (def normal-form-novar-noblank-spec (make-nform-spec ::subject-novar-noblank pred-objs-novar-noblank-spec)) -;; Subject Predicate Object (List) - -(def empty-map-spec - (s/map-of any? any? :max-count 0 :conform-keys true :into [])) - -#?(:clj - (defmacro make-nform-no-po-spec [subj-list-spec] - `(s/map-of ~subj-list-spec empty-map-spec - :conform-keys true :into []))) - -(def normal-form-no-po-spec - (make-nform-no-po-spec ::subject-coll)) - -(def normal-form-no-po-nopath-spec - (make-nform-no-po-spec ::subject-coll-nopath)) - -(def normal-form-no-po-novar-spec - (make-nform-no-po-spec ::subject-coll-novar)) - ;; Triple Vectors (def triple-vec-spec @@ -276,7 +269,7 @@ (def triple-vec-novar-noblank-spec (s/tuple ::subject-novar-noblank ::predicate-novar ::object-novar-noblank)) -;; Triple Vectors (List, no predicates + objects) +;; Triple Vectors (Coll, no predicates + objects) (def triple-vec-no-po-spec (s/tuple ::subject-coll)) @@ -292,20 +285,17 @@ (def triple-spec (s/or :triple.vec/spo triple-vec-spec :triple.vec/s triple-vec-no-po-spec - :triple.nform/spo normal-form-spec - :triple.nform/s normal-form-no-po-spec)) + :triple.nform/spo normal-form-spec)) (def triple-nopath-spec (s/or :triple.vec/spo triple-vec-nopath-spec :triple.vec/s triple-vec-no-po-nopath-spec - :triple.nform/spo normal-form-nopath-spec - :triple.nform/s normal-form-no-po-nopath-spec)) + :triple.nform/spo normal-form-nopath-spec)) (def triple-novar-spec (s/or :triple.vec/spo triple-vec-novar-spec :triple.vec/s triple-vec-no-po-novar-spec - :triple.nform/spo normal-form-novar-spec - :triple.nform/s normal-form-no-po-nopath-spec)) + :triple.nform/spo normal-form-novar-spec)) (def triple-noblank-spec (s/or :triple.vec/spo triple-vec-noblank-spec @@ -364,7 +354,6 @@ (s/coll-of (s/or :triple.vec/spo triple-vec-nopath-spec :triple.vec/s triple-vec-no-po-nopath-spec :triple.nform/spo normal-form-nopath-spec - :triple.nform/s normal-form-no-po-nopath-spec :triple.quad/gspo quad-nopath-spec) :kind vector?)) @@ -372,7 +361,6 @@ (s/coll-of (s/or :triple.vec/spo triple-vec-novar-spec :triple.vec/s triple-vec-no-po-novar-spec :triple.nform/spo normal-form-novar-spec - :triple.nform/s normal-form-no-po-novar-spec :triple.quad/gspo quad-novar-spec) :kind vector?)) diff --git a/src/main/com/yetanalytics/flint/validate/variable.cljc b/src/main/com/yetanalytics/flint/validate/variable.cljc index 68789e7..f906592 100644 --- a/src/main/com/yetanalytics/flint/validate/variable.cljc +++ b/src/main/com/yetanalytics/flint/validate/variable.cljc @@ -130,9 +130,6 @@ [] spo-pairs)) -(defmethod get-scope-vars :triple.nform/s [[_ s]] - (get-scope-vars s)) - ;; Path (defmethod get-scope-vars :triple/path [[_ p]] diff --git a/src/test/com/yetanalytics/flint/format/triple_test.cljc b/src/test/com/yetanalytics/flint/format/triple_test.cljc index af775c6..951f756 100644 --- a/src/test/com/yetanalytics/flint/format/triple_test.cljc +++ b/src/test/com/yetanalytics/flint/format/triple_test.cljc @@ -49,8 +49,9 @@ {:pretty? true}))) (is (= "( ?x ?y ) ." (f/format-ast - '[:triple.nform/s - [[[:triple/list [[:ax/var ?x] [:ax/var ?y]]] []]]] + '[:triple.nform/spo + [[[:triple/list [[:ax/var ?x] [:ax/var ?y]]] + [:triple.nform/po-empty []]]]] {:pretty? true}))) (is (= "\"v\" :p ( 1 2 ( 3 ) ) ." (f/format-ast diff --git a/src/test/com/yetanalytics/flint/spec/triple_test.cljc b/src/test/com/yetanalytics/flint/spec/triple_test.cljc index c026104..87d0bc9 100644 --- a/src/test/com/yetanalytics/flint/spec/triple_test.cljc +++ b/src/test/com/yetanalytics/flint/spec/triple_test.cljc @@ -61,7 +61,7 @@ (is (->> '{?s {(cat :x/one :x/two) #{?o}}} (s/explain-data ts/triple-nopath-spec) ::s/problems - (filter #(-> % :path first (= :triple.nform/spo))) + (filter #(-> % :path butlast (= [:triple.nform/spo 1 :triple.nform/po 0]))) (map :val) (every? (partial = '(cat :x/one :x/two)))))) (testing "with list and blank nodes" @@ -106,11 +106,11 @@ [:triple/list [[:ax/literal 2]]]]]]] (s/conform ts/triple-spec '[(1 ?x (2))]))) - (is (= '[:triple.nform/s + (is (= '[:triple.nform/spo [[[:triple/list [[:ax/literal 1] [:ax/var ?x] [:triple/list [[:ax/literal 2]]]]] - []]]] + [:triple.nform/po-empty []]]]] (s/conform ts/triple-spec '{(1 ?x (2)) {}}))) (is (= '[:triple.vec/s