diff --git a/.gitignore b/.gitignore index 61efd89..c4e4972 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,27 @@ +.calva/output-window/ +.classpath +.clj-kondo/.cache +.cpcache +.DS_Store +.eastwood +.factorypath +.hg/ +.hgignore +.java-version +.lein-* +.lsp/.cache +.lsp/sqlite.db +.nrepl-history +.nrepl-port +.portal +.project +.rebel_readline_history +.settings +.socket-repl-port +.sw* +.vscode *.class *.jar -/.lein-* -/.nrepl-history -/.nrepl-port -/checkouts -/classes -/node_modules -/package-lock.json -/pom.xml -/pom.xml.asc -/scratch.* -/target -/yarn.lock \ No newline at end of file +*.swp +*~ +target diff --git a/boot.properties b/boot.properties deleted file mode 100644 index d83103d..0000000 --- a/boot.properties +++ /dev/null @@ -1,3 +0,0 @@ -BOOT_CLOJURE_NAME=org.clojure/clojure -BOOT_CLOJURE_VERSION=1.10.0 -BOOT_VERSION=2.8.2 diff --git a/build.boot b/build.boot deleted file mode 100644 index 13717cb..0000000 --- a/build.boot +++ /dev/null @@ -1,73 +0,0 @@ -(task-options! - pom {:project 'com.paren/serene - :version "0.0.2" - :description "Generate clojure.spec with GraphQL and extend GraphQL with clojure.spec" - :url "https://github.com/paren-com/serene" - :scm {:url "https://github.com/paren-com/serene"} - :license {"Eclipse Public License" "http://www.eclipse.org/legal/epl-v20.html"}}) - -(set-env! - :source-paths #{} - :resource-paths #{"sources/main" - "resources/main"}) - -(merge-env! - :dependencies [['org.clojure/clojure (clojure-version)]]) - -(merge-env! - :dependencies '[[adzerk/boot-cljs "2.1.5" :scope "test"] - [com.walmartlabs/lacinia "0.31.0" :scope "test"] - [crisptrutski/boot-cljs-test "0.3.5-SNAPSHOT" :scope "test"] - [doo "0.1.8" :scope "test"] - [expound "0.7.2" :scope "test"] - [fipp "0.6.14"] - [http-kit "2.3.0"] - [metosin/bat-test "0.4.2" :scope "test"] - [org.clojure/clojurescript "1.10.439"] - [org.clojure/data.json "0.2.6"] - [org.clojure/spec.alpha "0.2.176"] - [org.clojure/test.check "0.10.0-alpha3" :scope "test"] - [samestep/boot-refresh "0.1.0" :scope "test"]]) - -(require - '[crisptrutski.boot-cljs-test :refer [test-cljs]] - '[metosin.bat-test :refer [bat-test]] - '[samestep.boot-refresh :refer [refresh]]) - -(deftask build [] - (comp - (pom) - (jar) - (install))) - -(deftask deploy [] - (comp - (build) - (push :repo "clojars"))) - -(deftask test-env [] - (merge-env! :resource-paths #{"sources/test" - "resources/test"}) - identity) - -(ns-unmap *ns* 'test) -(deftask test [] - (comp - (test-env) - (bat-test) - (test-cljs - :cljs-opts {:parallel-build true} - :ids ["paren/serene_test"] - :js-env :node))) - -(deftask dev-env [] - (merge-env! :resource-paths #{"sources/dev" - "resources/dev"}) - identity) - -(deftask dev [] - (comp - (dev-env) - (repl :server true) - (watch) - (refresh))) diff --git a/build.clj b/build.clj new file mode 100644 index 0000000..44784ec --- /dev/null +++ b/build.clj @@ -0,0 +1,87 @@ +(ns build + (:refer-clojure :exclude [test]) + (:require [clojure.tools.deps :as t] + [clojure.tools.build.api :as b] + [deps-deploy.maven-settings :as ms] + [deps-deploy.deps-deploy :as dd])) + +(def lib 'neax.clojure.serene/serene) +(def version "0.0.3-SNAPSHOT") +(def class-dir "target/classes") +(def uber-file (str "target/serene.jar")) +(def basis (b/create-basis {:project "deps.edn"})) + +(def repo-url "https://maven.pkg.github.com/neaxplore/xplore-backend-lambda-functions") + +(defn test "Run all the tests." [opts] + (println "\nRunning tests...") + (let [basis (b/create-basis {:aliases [:test]}) + combined (t/combine-aliases basis [:test]) + cmds (b/java-command + {:basis basis + :java-opts (:jvm-opts combined) + :main 'clojure.main + :main-args ["-m" "cognitect.test-runner"]}) + {:keys [exit]} (b/process cmds)] + (when-not (zero? exit) (throw (ex-info "Tests failed" {})))) + opts) + +(defn- jar-opts [opts] + (assoc opts + :lib lib :version version + :jar-file (format "target/%s-%s.jar" lib version) + :scm {:tag (str "v" version)} + :basis (b/create-basis {}) + :class-dir class-dir + :target "target" + :src-dirs ["src"])) + +(defn compile-ns [opts] + (b/compile-clj {:basis basis + :src-dirs ["src"] + :class-dir class-dir + :compile-opts {:direct-linking true + :elide-meta [:file :line :added]}})) + +(defn clean [path] + (b/delete {:path path})) + +(defn uber [_] + (println (format "building: %s %s" lib version)) + (clean "target/classes") + (b/copy-dir {:src-dirs ["src"] + :target-dir class-dir}) + (compile-ns nil) + ;; only remove uberjar after successful compilation + (clean uber-file) + (b/uber {:class-dir class-dir + :uber-file uber-file + :basis basis + :main lib})) + +(defn ci "Run the CI pipeline of tests (and build the JAR)." [opts] + (b/delete {:path "target"}) + (test nil) + (let [opts (jar-opts opts)] + (println "\nWriting pom.xml...") + (b/write-pom opts) + (println "\nCopying source...") + (b/copy-dir {:src-dirs ["resources" "src"] :target-dir class-dir}) + (compile-ns nil) + (println "\nBuilding JAR...") + (b/jar opts)) + opts) + +(defn install "Install the JAR locally." [opts] + (let [opts (jar-opts opts)] + (b/install opts)) + opts) + +(defn deploy "Deploy the JAR to Github." [opts] + (let [{:keys [jar-file] :as opts} (jar-opts opts)] + (dd/deploy {:installer :remote :artifact (b/resolve-path jar-file) + :repository (assoc-in (ms/deps-repo-by-id-plaintext "github") + ["github" :url] + repo-url) + :pom-file (b/pom-path (select-keys opts [:lib :class-dir]))})) + opts) diff --git a/deps.edn b/deps.edn new file mode 100644 index 0000000..5c5bceb --- /dev/null +++ b/deps.edn @@ -0,0 +1,41 @@ +{:paths ["src" "resources"] + :deps {fipp/fipp {:mvn/version "0.6.26"} + org.clojure/clojure {:mvn/version "1.12.0-rc2"} + org.clojure/spec.alpha {:mvn/version "0.5.238"}} + :aliases {:build ;; clj -T:build uber + {:deps {io.github.clojure/tools.build {:mvn/version "0.10.5"} + io.github.se-neaxplore/deps-deploy {:git/tag "v0.0.1" :git/sha "01c90a7"} + org.clojure/tools.deps {:mvn/version "0.20.1440"}} + :ns-default build} + :cider {:extra-paths ["test" "target/classes"] + :extra-deps {cider/cider-nrepl {:mvn/version "0.50.2"} + com.walmartlabs/lacinia {:mvn/version "1.2.2"} + org.clojure/test.check {:mvn/version "1.1.1"}} + :main-opts ["-m" "nrepl.cmdline" + "--middleware" "[cider.nrepl/cider-middleware]" + "--interactive"]} + :codox {:extra-deps {codox/codox {:mvn/version "0.10.8"} + com.balloneij/familiar-codox-theme {:mvn/version "0.1.0"}} + :exec-fn codox.main/generate-docs + :exec-args {:source-paths ["src"] + :source-uri "https://github.com/se-neaxplore/serene/blob/8ccb4453826c4011aa4b9647ceb63ba0bbc7191e/{filepath}#L{line}" + :themes [:familiar]}} + :format/check {:deps {dev.weavejester/cljfmt {:mvn/version "0.12.0"}} + :main-opts ["-m" "cljfmt.main" "check"]} + :format/fix {:deps {dev.weavejester/cljfmt {:mvn/version "0.12.0"}} + :main-opts ["-m" "cljfmt.main" "fix"]} + :kaocha ;; clj -M:kaocha + {:extra-deps {com.walmartlabs/lacinia {:mvn/version "1.2.2"} + lambdaisland/kaocha {:mvn/version "1.91.1392"} + lambdaisland/kaocha-cloverage {:mvn/version "1.1.89"} + lambdaisland/kaocha-junit-xml {:mvn/version "1.17.101"} + org.clojure/test.check {:mvn/version "1.1.1"}} + :extra-paths ["test"] + :main-opts ["-m" "kaocha.runner"]} + :test {:extra-paths ["test"] + :extra-deps {io.github.cognitect-labs/test-runner + {:git/tag "v0.5.1" :git/sha "dfb30dd"} + org.clojure/test.check {:mvn/version "1.1.1"} + com.walmartlabs/lacinia {:mvn/version "1.2.2"}} + :main-opts ["-m" "cognitect.test-runner"] + :exec-fn cognitect.test-runner.api/test}}} diff --git a/sources/dev/paren/serene/dev.clj b/dev/dev/paren/serene/dev.clj similarity index 100% rename from sources/dev/paren/serene/dev.clj rename to dev/dev/paren/serene/dev.clj diff --git a/resources/main/paren/serene/IntrospectionQuery.graphql b/resources/paren/serene/IntrospectionQuery.graphql similarity index 100% rename from resources/main/paren/serene/IntrospectionQuery.graphql rename to resources/paren/serene/IntrospectionQuery.graphql diff --git a/resources/test/paren/serene/schema.graphql b/resources/paren/serene/schema.graphql similarity index 93% rename from resources/test/paren/serene/schema.graphql rename to resources/paren/serene/schema.graphql index 72ebf7e..0f66a56 100644 --- a/resources/test/paren/serene/schema.graphql +++ b/resources/paren/serene/schema.graphql @@ -2,6 +2,8 @@ scalar Scalar_Any scalar Scalar_Email +scalar Scalar_Instant + interface Interface_ID { id: ID! } @@ -11,7 +13,7 @@ interface Interface_EmailOrUsername { username(downcase: Boolean! = false): String } -type Object_EmailOrUsername implements Interface_EmailOrUsername Interface_ID { +type Object_EmailOrUsername implements Interface_EmailOrUsername & Interface_ID { id: ID! email: Scalar_Email username(downcase: Boolean! = false): String @@ -19,7 +21,7 @@ type Object_EmailOrUsername implements Interface_EmailOrUsername Interface_ID { input InputObject_EmailOrUsername { email: Scalar_Email - username(downcase: Boolean! = false): String + username: String } type Object_IffHasChildThenChild implements Interface_ID { diff --git a/sources/main/paren/serene/schema.cljc b/sources/main/paren/serene/schema.cljc deleted file mode 100644 index c86627e..0000000 --- a/sources/main/paren/serene/schema.cljc +++ /dev/null @@ -1,228 +0,0 @@ -(ns paren.serene.schema - (:require - [clojure.spec.alpha :as s] - [clojure.walk :as walk] - #?@(:clj [[clojure.data.json :as json] - [clojure.java.io :as io] - [org.httpkit.client :as http]])) - #?(:cljs (:require-macros - [paren.serene.schema :refer [slurp-query]]))) - -(s/def ::Directive (s/keys - :req-un [::__typename - ::args - ::description - ::locations - ::name])) - -(s/def ::EnumValue (s/keys - :req-un [::__typename - ::deprecationReason - ::description - ::isDeprecated - ::name])) - -(s/def ::Field (s/keys - :req-un [::__typename - ::args - ::deprecationReason - ::description - ::isDeprecated - ::name - ::type])) - -(s/def ::InputValue (s/keys - :req-un [::__typename - ::defaultValue - ::description - ::name - ::type])) - -(s/def ::Type (s/and - (s/keys - :req-un [::__typename - ::description - ::enumValues - ::fields - ::inputFields - ::interfaces - ::kind - ::name - ::possibleTypes]) - (s/conformer - (fn ensure-typename-field - [{:as m - :keys [fields kind]}] - (if (and - (= kind :OBJECT) - (->> fields - (filter #(= (:name %) :__typename)) - first - nil?)) - (update m :fields conj {:__typename :__Field - :args [] - :deprecationReason nil - :description nil - :isDeprecated false - :name :__typename - :type {:__typename :__Type - :kind :NON_NULL - :name nil - :ofType {:__typename :__Type - :kind :SCALAR - :name :String - :ofType nil}}}) - m))))) - -(s/def ::TypeRef (s/and - (s/keys - :req-un [::__typename - ::kind - ::name] - :opt-un [::ofType]) - (fn not-a-type [m] - (empty? - (select-keys m [:enumValues - :fields - :inputFields - :interfaces - :possibleTypes]))))) - -(s/def ::__typename simple-keyword?) - -(s/def ::args (s/coll-of ::InputValue :kind vector?)) - -(s/def ::defaultValue (s/nilable string?)) - -(s/def ::deprecationReason (s/nilable string?)) - -(s/def ::description (s/nilable string?)) - -(s/def ::enumValues (s/nilable (s/coll-of ::EnumValue - :kind vector?))) - -(s/def ::fields (s/nilable (s/coll-of ::Field - :kind vector?))) - -(s/def ::inputFields (s/nilable (s/coll-of ::InputValue - :kind vector?))) - -(s/def ::interfaces (s/nilable (s/coll-of ::TypeRef - :kind vector?))) - -(s/def ::isDeprecated boolean?) - -(s/def ::kind simple-keyword?) - -(s/def ::locations (s/coll-of #{:ARGUMENT_DEFINITION - :ENUM - :ENUM_VALUE - :FIELD - :FIELD_DEFINITION - :FRAGMENT_DEFINITION - :FRAGMENT_SPREAD - :INLINE_FRAGMENT - :INPUT_FIELD_DEFINITION - :INPUT_OBJECT - :INTERFACE - :MUTATION - :OBJECT - :QUERY - :SCALAR - :SCHEMA - :SUBSCRIPTION - :UNION} - :kind vector?)) - -(s/def ::name (s/nilable simple-keyword?)) - -(s/def ::ofType (s/nilable ::TypeRef)) - -(s/def ::possibleTypes (s/nilable (s/coll-of ::TypeRef - :kind vector?))) - -(s/def ::type ::TypeRef) - -(s/def ::queryType (s/keys :req-un [::name])) - -(s/def ::mutationType (s/nilable (s/keys :req-un [::name]))) - -(s/def ::subsriptionType (s/nilable (s/keys :req-un [::name]))) - -(s/def ::directives (s/coll-of ::Directive - :kind vector?)) - -(s/def ::types (s/coll-of ::Type :kind vector?)) - -(s/def ::__schema (s/keys - :req-un [::__typename - ::queryType - ::mutationType - ::subscriptionType - ::directives - ::types])) - -(s/def ::Schema ::__schema) - -(s/def ::data (s/keys - :req-un [::__schema])) - -(s/def ::errors (s/nilable empty?)) - -(s/def ::response (s/keys - :req-un [::data] - :opt-un [::errors])) - -(defn ^:private normalize - "* keywordizes all keys and some specific values - * replaces non-serializable collections with serializable collections - * converts sets and sequential collections into sorted vectors " - [form] - (->> form - walk/keywordize-keys - (walk/postwalk (fn [x] - (cond - (map? x) (->> x - (map (fn [[k v]] - [k - (case k - (:__typename :kind :name) (keyword v) - :locations (mapv keyword v) - v)])) - (into (sorted-map))) - (or - (set? x) - (sequential? x)) (->> x (sort-by :name) vec) - :else x))))) - -(s/def ::schema (s/and - (s/conformer normalize) - (s/or - :response ::response - :data ::data - :Schema ::Schema) - (s/conformer - #(case (key %) - :response (-> % val :data :__schema) - :data (-> % val :__schema) - :Schema (-> % val))))) - -#?(:clj (defmacro ^:private slurp-query [] - (-> "paren/serene/IntrospectionQuery.graphql" - io/resource - slurp))) - -(def query (slurp-query)) - -#?(:clj (defn fetch - ([url] - (fetch url {})) - ([url opts] - (-> {:url url - :method :post - :body (json/write-str {:query query})} - (merge opts) - http/request - deref - :body - (json/read-str :key-fn keyword))))) diff --git a/sources/main/paren/serene.cljc b/src/paren/serene.cljc similarity index 100% rename from sources/main/paren/serene.cljc rename to src/paren/serene.cljc diff --git a/sources/main/paren/serene/compiler.cljc b/src/paren/serene/compiler.cljc similarity index 100% rename from sources/main/paren/serene/compiler.cljc rename to src/paren/serene/compiler.cljc diff --git a/sources/main/paren/serene/compiler/transducers.cljc b/src/paren/serene/compiler/transducers.cljc similarity index 98% rename from sources/main/paren/serene/compiler/transducers.cljc rename to src/paren/serene/compiler/transducers.cljc index b356c7b..8eff89e 100644 --- a/sources/main/paren/serene/compiler/transducers.cljc +++ b/src/paren/serene/compiler/transducers.cljc @@ -49,7 +49,7 @@ (if-let [ext (and (not alias?) (extend-fn schema-key))] - (assoc spec ::compiler/form `(s/and ~form ~ext)) + (assoc spec ::compiler/form `(s/and ~ext ~form)) spec)))) ;; Takes a function (or map) that will receive an object type spec name and diff --git a/src/paren/serene/schema.cljc b/src/paren/serene/schema.cljc new file mode 100644 index 0000000..70b5d7c --- /dev/null +++ b/src/paren/serene/schema.cljc @@ -0,0 +1,211 @@ +(ns paren.serene.schema + (:require + [clojure.spec.alpha :as s] + [clojure.walk :as walk] + [clojure.java.io :as io])) + +(s/def ::Directive (s/keys + :req-un [::__typename + ::args + ::description + ::locations + ::name])) + +(s/def ::EnumValue (s/keys + :req-un [::__typename + ::deprecationReason + ::description + ::isDeprecated + ::name])) + +(s/def ::Field (s/keys + :req-un [::__typename + ::args + ::deprecationReason + ::description + ::isDeprecated + ::name + ::type])) + +(s/def ::InputValue (s/keys + :req-un [::__typename + ::defaultValue + ::description + ::name + ::type])) + +(s/def ::Type (s/and + (s/keys + :req-un [::__typename + ::description + ::enumValues + ::fields + ::inputFields + ::interfaces + ::kind + ::name + ::possibleTypes]) + (s/conformer + (fn ensure-typename-field + [{:as m + :keys [fields kind]}] + (if (and + (= kind :OBJECT) + (->> fields + (filter #(= (:name %) :__typename)) + first + nil?)) + (update m :fields conj {:__typename :__Field + :args [] + :deprecationReason nil + :description nil + :isDeprecated false + :name :__typename + :type {:__typename :__Type + :kind :NON_NULL + :name nil + :ofType {:__typename :__Type + :kind :SCALAR + :name :String + :ofType nil}}}) + m))))) + +(s/def ::TypeRef (s/and + (s/keys + :req-un [::__typename + ::kind + ::name] + :opt-un [::ofType]) + (fn not-a-type [m] + (empty? + (select-keys m [:enumValues + :fields + :inputFields + :interfaces + :possibleTypes]))))) + +(s/def ::__typename simple-keyword?) + +(s/def ::args (s/coll-of ::InputValue :kind vector?)) + +(s/def ::defaultValue (s/nilable string?)) + +(s/def ::deprecationReason (s/nilable string?)) + +(s/def ::description (s/nilable string?)) + +(s/def ::enumValues (s/nilable (s/coll-of ::EnumValue + :kind vector?))) + +(s/def ::fields (s/nilable (s/coll-of ::Field + :kind vector?))) + +(s/def ::inputFields (s/nilable (s/coll-of ::InputValue + :kind vector?))) + +(s/def ::interfaces (s/nilable (s/coll-of ::TypeRef + :kind vector?))) + +(s/def ::isDeprecated boolean?) + +(s/def ::kind simple-keyword?) + +(s/def ::locations (s/coll-of #{:ARGUMENT_DEFINITION + :ENUM + :ENUM_VALUE + :FIELD + :FIELD_DEFINITION + :FRAGMENT_DEFINITION + :FRAGMENT_SPREAD + :INLINE_FRAGMENT + :INPUT_FIELD_DEFINITION + :INPUT_OBJECT + :INTERFACE + :MUTATION + :OBJECT + :QUERY + :SCALAR + :SCHEMA + :SUBSCRIPTION + :UNION} + :kind vector?)) + +(s/def ::name (s/nilable simple-keyword?)) + +(s/def ::ofType (s/nilable ::TypeRef)) + +(s/def ::possibleTypes (s/nilable (s/coll-of ::TypeRef + :kind vector?))) + +(s/def ::type ::TypeRef) + +(s/def ::queryType (s/keys :req-un [::name])) + +(s/def ::mutationType (s/nilable (s/keys :req-un [::name]))) + +(s/def ::subsriptionType (s/nilable (s/keys :req-un [::name]))) + +(s/def ::directives (s/coll-of ::Directive + :kind vector?)) + +(s/def ::types (s/coll-of ::Type :kind vector?)) + +(s/def ::__schema (s/keys + :req-un [::__typename + ::queryType + ::mutationType + ::subscriptionType + ::directives + ::types])) + +(s/def ::Schema ::__schema) + +(s/def ::data (s/keys + :req-un [::__schema])) + +(s/def ::errors (s/nilable empty?)) + +(s/def ::response (s/keys + :req-un [::data] + :opt-un [::errors])) + +(defn ^:private normalize + "* keywordizes all keys and some specific values + * replaces non-serializable collections with serializable collections + * converts sets and sequential collections into sorted vectors " + [form] + (->> form + walk/keywordize-keys + (walk/postwalk (fn [x] + (cond + (map? x) (->> x + (map (fn [[k v]] + [k + (case k + (:__typename :kind :name) (keyword v) + :locations (mapv keyword v) + v)])) + (into (sorted-map))) + (or + (set? x) + (sequential? x)) (->> x (sort-by :name) vec) + :else x))))) + +(s/def ::schema (s/and + (s/conformer normalize) + (s/or + :response ::response + :data ::data + :Schema ::Schema) + (s/conformer + #(case (key %) + :response (-> % val :data :__schema) + :data (-> % val :__schema) + :Schema (-> % val))))) + +(defmacro ^:private slurp-query [] + `(-> "paren/serene/IntrospectionQuery.graphql" + io/resource + slurp)) + +(def query (slurp-query)) diff --git a/sources/test/paren/serene_test.cljc b/test/paren/serene_test.cljc similarity index 65% rename from sources/test/paren/serene_test.cljc rename to test/paren/serene_test.cljc index abf0dc2..ece1d34 100644 --- a/sources/test/paren/serene_test.cljc +++ b/test/paren/serene_test.cljc @@ -1,42 +1,36 @@ (ns paren.serene-test (:require + [clojure.java.io :as io] [clojure.spec.alpha :as s] - [clojure.spec.test.alpha :as st] [clojure.string :as str] [clojure.test :as t] [clojure.test.check] - [clojure.walk :as walk] + [com.walmartlabs.lacinia :as lacinia] + [com.walmartlabs.lacinia.parser.schema :as lacinia.parser.schema] + [com.walmartlabs.lacinia.schema :as lacinia.schema] [paren.serene :as serene] - [paren.serene.schema :as schema] - #?@(:clj [[clojure.data.json :as json] - [clojure.java.io :as io] - [com.walmartlabs.lacinia :as lacinia] - [com.walmartlabs.lacinia.parser.schema :as lacinia.parser.schema] - [com.walmartlabs.lacinia.schema :as lacinia.schema]] - :cljs [[doo.runner :include-macros true]])) - #?(:cljs (:require-macros - [paren.serene-test :refer [test-spec test-specs]]))) + [paren.serene.schema :as schema])) (s/check-asserts true) -#?(:clj (defn ^:private get-introspection-query-response [] - (let [sdl (-> "paren/serene/schema.graphql" io/resource slurp) - edn (lacinia.parser.schema/parse-schema sdl {}) - edn (update edn :scalars (fn [scalars] - (->> scalars - (map (fn [[k v]] - [k (assoc v +(defn ^:private get-introspection-query-response [] + (let [sdl (slurp (io/resource "paren/serene/schema.graphql")) + edn (lacinia.parser.schema/parse-schema sdl {}) + edn (update edn :scalars (fn [scalars] + (->> scalars + (map (fn [[k v]] + [k (assoc v :parse identity :serialize identity)])) - (into {})))) - schema (lacinia.schema/compile edn) - resp (lacinia/execute schema schema/query {} {})] - resp))) + (into {})))) + schema (lacinia.schema/compile edn) + resp (lacinia/execute schema schema/query {} {})] + resp)) (defn ^:private email? [x] (and - (string? x) - (str/includes? x "@"))) + (string? x) + (str/includes? x "@"))) (s/def ::email email?) @@ -47,9 +41,9 @@ [{:as m :keys [email username]}] (and - (map? m) - (or email username) - (not (and email username)))) + (map? m) + (or email username) + (not (and email username)))) (s/def ::map-of-email-or-username map-of-email-or-username?) @@ -58,14 +52,14 @@ [{:as m :keys [hasChild child]}] (and - (map? m) - (or - (and - (true? hasChild) - (iff-has-child-then-child? child)) - (and - (false? hasChild) - (not (iff-has-child-then-child? child)))))) + (map? m) + (or + (and + (true? hasChild) + (iff-has-child-then-child? child)) + (and + (false? hasChild) + (not (iff-has-child-then-child? child)))))) (s/def ::iff-has-child-then-child iff-has-child-then-child?) @@ -146,11 +140,11 @@ (test-spec :gql/Scalar_Any {:valid [1 1.0 true {} () nil :kw "str"]})) (t/testing "fields and input values" (test-specs - [:gql.InputObject_EmailOrUsername/email - :gql.Interface_EmailOrUsername/email - :gql.Object_EmailOrUsername/email] - {:valid ["email@example" nil] - :invalid ["example"]}) + [:gql.InputObject_EmailOrUsername/email + :gql.Interface_EmailOrUsername/email + :gql.Object_EmailOrUsername/email] + {:valid ["email@example" nil] + :invalid ["example"]}) (test-spec :gql.Mutation/createUser {:valid ["ID"] :invalid [nil 1 true]}) (test-spec :gql.Query/randPosInt {:valid [1 42] @@ -161,19 +155,19 @@ :invalid ["str" 1]})) (t/testing "objects, interfaces, input objects, and args" (test-specs - [:gql/InputObject_EmailOrUsername - :gql/Interface_EmailOrUsername - :gql/Object_EmailOrUsername] - {:valid [{:id "ID" - :email "email@example"} - {:id "ID" - :username "user"}] - :invalid [{:id "ID"} - {:id "ID" - :email "email@example" - :username "user"} - {:id "ID" - :email true}]}) + [:gql/InputObject_EmailOrUsername + :gql/Interface_EmailOrUsername + :gql/Object_EmailOrUsername] + {:valid [{:id "ID" + :email "email@example"} + {:id "ID" + :username "user"}] + :invalid [{:id "ID"} + {:id "ID" + :email "email@example" + :username "user"} + {:id "ID" + :email true}]}) (test-spec :gql.Query.randPosInt/&args {:valid [{:noDefault 1 :seed 1}] :invalid [{} @@ -181,23 +175,23 @@ {:seed true}]})) (t/testing "union, union-returning fields, and interface-returning fields" (test-specs - [:gql/Interface_ID - :gql/Union_ID - :gql.Query/interfaceID - :gql.Query/unionID] - {:valid [{:id "ID" - :email "email@example"} - {:id "ID" - :hasChild false}] - :invalid [{:id "ID" - :hasChild false - :child {:id "ID" - :hasChild false}}]})) + [:gql/Interface_ID + :gql/Union_ID + :gql.Query/interfaceID + :gql.Query/unionID] + {:valid [{:id "ID" + :email "email@example"} + {:id "ID" + :hasChild false}] + :invalid [{:id "ID" + :hasChild false + :child {:id "ID" + :hasChild false}}]})) (test-specs - [:gql.InputObject_EmailOrUsername/email - :gql.Interface_EmailOrUsername/email - :gql.Object_EmailOrUsername/email] - {:valid ["foo@bar"] - :invalid ["foobar"]}))) + [:gql.InputObject_EmailOrUsername/email + :gql.Interface_EmailOrUsername/email + :gql.Object_EmailOrUsername/email] + {:valid ["foo@bar"] + :invalid ["foobar"]}))) #?(:cljs (doo.runner/doo-tests))