diff --git a/src/venia/core.cljc b/src/venia/core.cljc index 9d0bb92..436063d 100644 --- a/src/venia/core.cljc +++ b/src/venia/core.cljc @@ -103,13 +103,30 @@ (interpose ",") (apply str)))) +(defn variable-type->str + [[def-type ttype]] + (case def-type + :simple-type + (name ttype) + + :complex-type + (let [required-str (when (:type/required? ttype) "!")] + (str + (cond + (:type/type ttype) + (name (:type/type ttype)) + + (= :list (:type/kind ttype)) + (str "[" (variable-type->str (:type.list/items ttype)) "]")) + required-str)))) + (defn variables->str "Given a vector of variable maps, formats them and concatenates to string. E.g. (variables->str [{:variable/name \"id\" :variable/type :Int}]) => \"$id: Int\"" [variables] (->> (for [{var-name :variable/name var-type :variable/type var-default :variable/default} variables] - (str "$" var-name ":" (name var-type) (when var-default (str "=" (arg->str var-default))))) + (str "$" var-name ":" (variable-type->str var-type) (when var-default (str "=" (arg->str var-default))))) (interpose ",") (apply str))) diff --git a/src/venia/spec.cljc b/src/venia/spec.cljc index 25af04e..90b8793 100644 --- a/src/venia/spec.cljc +++ b/src/venia/spec.cljc @@ -148,7 +148,18 @@ (s/def :venia/operation (s/keys :req [:operation/type :operation/name])) (s/def :variable/name string?) -(s/def :variable/type keyword?) +(s/def :variable/type + (s/or :simple-type keyword? + :complex-type :variable/complex-type)) +(s/def :variable/complex-type + (s/keys :req [(or :type/type :type/kind)] + :opt [:type/required? :type.list/items])) + +(s/def :type/type keyword?) +(s/def :type/kind keyword?) +(s/def :type/required? boolean?) +(s/def :type.list/items :variable/type) + (s/def :query/variable (s/keys :req [:variable/name :variable/type] :opt [:variable/default])) (s/def :venia/variables (s/coll-of :query/variable :min-count 1)) diff --git a/test/venia/core_test.cljc b/test/venia/core_test.cljc index 5e3dda7..bee5b75 100644 --- a/test/venia/core_test.cljc +++ b/test/venia/core_test.cljc @@ -48,21 +48,41 @@ :venia/nested-field-children [[:venia/field :name] [:venia/field :email]]}]])))) +(deftest variable-type->str-test + (is (= "Int" (v/variable-type->str [:simple-type :Int]))) + (is (= "Int" (v/variable-type->str [:complex-type {:type/type :Int}]))) + (is (= "Int!" (v/variable-type->str [:complex-type {:type/type :Int + :type/required? true}]))) + (is (= "[Int]!" (v/variable-type->str [:complex-type {:type/kind :list + :type.list/items [:simple-type :Int] + :type/required? true}]))) + (is (= "[Int!]!" (v/variable-type->str [:complex-type {:type/kind :list + :type.list/items [:complex-type {:type/type :Int + :type/required? true}] + :type/required? true}])))) + (deftest variables->str-test (is (= "$id:Int" (v/variables->str [{:variable/name "id" - :variable/type :Int}]))) + :variable/type [:simple-type :Int]}]))) (is (= "$id:Int=2" (v/variables->str [{:variable/name "id" - :variable/type :Int + :variable/type [:simple-type :Int] :variable/default 2}]))) + (is (= "$id:[Int!]!=2" (v/variables->str [{:variable/name "id" + :variable/type + [:complex-type {:type/kind :list + :type.list/items [:complex-type {:type/type :Int + :type/required? true}] + :type/required? true}] + :variable/default 2}]))) (is (= "$id:Int,$name:String" (v/variables->str [{:variable/name "id" - :variable/type :Int} + :variable/type [:simple-type :Int]} {:variable/name "name" - :variable/type :String}]))) + :variable/type [:simple-type :String]}]))) (is (= "$id:Int=1,$name:String=\"my-name\"" (v/variables->str [{:variable/name "id" - :variable/type :Int + :variable/type [:simple-type :Int] :variable/default 1} {:variable/name "name" - :variable/type :String + :variable/type [:simple-type :String] :variable/default "my-name"}]))) (is (= "" (v/variables->str nil))) (is (= "" (v/variables->str [])))) @@ -243,6 +263,24 @@ result (v/graphql-query data)] (is (= query-str result)))) + (testing "Should create a valid graphql query with complex variables" + (let [data {:venia/operation {:operation/type :query + :operation/name "employeeQuery"} + :venia/variables [{:variable/name "id" + :variable/type :Int} + {:variable/name "namelist" + :variable/type {:type/kind :list + :type.list/items {:type/type :String + :type/required? true} + :type/required? true}}] + :venia/queries [[:employee {:id :$id + :active true + :name :$namelist} + [:name :address [:friends [:name :email]]]]]} + query-str (str "query employeeQuery($id:Int,$namelist:[String!]!){employee(id:$id,active:true,name:$namelist){name,address,friends{name,email}}}") + result (v/graphql-query data)] + (is (= query-str result)))) + (testing "Should create a valid graphql query with variables, aliases and fragments" (let [data {:venia/operation {:operation/type :query :operation/name "employeeQuery"} diff --git a/test/venia/spec_test.cljc b/test/venia/spec_test.cljc index 89477a5..f352a21 100644 --- a/test/venia/spec_test.cljc +++ b/test/venia/spec_test.cljc @@ -1,8 +1,10 @@ (ns venia.spec-test (:require [venia.spec :as vs] - #?(:cljs [cljs.test :refer-macros [is are deftest testing]] - :clj - [clojure.test :refer :all]))) + #?(:cljs [cljs.test :refer-macros [is are deftest testing]] + :clj + [clojure.test :refer :all]) + #?(:clj [clojure.spec.alpha :as s] + :cljs [cljs.spec.alpha :as s]))) (deftest query->spec-simple-query (testing "Wrong data type - vector instead of map, should throw exception" @@ -112,9 +114,9 @@ (is (= [:venia/query-def {:venia/operation {:operation/type :query :operation/name "employeeQuery"} :venia/variables [{:variable/name "id" - :variable/type :Int} + :variable/type [:simple-type :Int]} {:variable/name "name" - :variable/type :String}] + :variable/type [:simple-type :String]}] :venia/fragments [{:fragment/name "comparisonFields" :fragment/type :Worker :fragment/fields [[:venia/field :name] [:venia/field :address] @@ -150,3 +152,27 @@ :venia/fragments [{:fragment/name "comparisonFields" :fragment/type :Worker :fragment/fields [:name :address [:friends [:name :email]]]}]}))))) + +(deftest variable-tests + (is (s/valid? :query/variable + {:variable/name "Foo" + :variable/type :Foo})) + (is (s/valid? :query/variable + {:variable/name "Foo" + :variable/type {:type/type :Int}})) + (is (s/valid? :query/variable + {:variable/name "Foo" + :variable/type {:type/type :Int + :type/required? true}})) + (is (s/valid? :query/variable + {:variable/name "Foo" + :variable/type {:type/kind :list + :type.list/items :Int + :type/required? true}})) + (is (s/valid? :query/variable + {:variable/name "Foo" + :variable/type {:type/kind :list + :type.list/items {:type/type :Int + :type/required? true} + :type/required? true}})) + )