Skip to content

Commit

Permalink
Introspect with @SpecifiedBy (#18)
Browse files Browse the repository at this point in the history
* resolve specifiedByUrl

* add test

* s/def

* apply review
  • Loading branch information
1e16miin authored Nov 4, 2024
1 parent 20296bc commit 5e1fca5
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 34 deletions.
4 changes: 3 additions & 1 deletion resources/com/walmartlabs/lacinia/introspection.edn
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
:inputFields {:type (list :__InputValue)
:resolve :input-fields}
:ofType {:type :__Type
:resolve :of-type}}}
:resolve :of-type}
:specifiedByUrl {:type String
:resolve :specified-by-url}}}

:__Field
{:fields
Expand Down
8 changes: 7 additions & 1 deletion src/com/walmartlabs/lacinia/introspection.clj
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,11 @@
(::type-map input-value)
(::default-value input-value)))

(defn ^:private resolve-specified-by-url
[_ _ {:keys [::category ::type-def] :as _value}]
(when (= :scalar category)
(:specified-by type-def)))

(defn introspection-schema
"Builds an returns the introspection schema, which can be merged into the user schema."
[]
Expand All @@ -296,4 +301,5 @@
:interfaces resolve-interfaces
:of-type resolve-of-type
:possible-types resolve-possible-types
:default-value default-value})))
:default-value default-value
:specified-by-url resolve-specified-by-url})))
3 changes: 2 additions & 1 deletion src/com/walmartlabs/lacinia/parser/schema.clj
Original file line number Diff line number Diff line change
Expand Up @@ -629,8 +629,9 @@
(s/def ::fn-map (s/map-of simple-keyword? ::field-fn))
(s/def ::parse ::schema/parse-or-serialize-fn)
(s/def ::serialize ::schema/parse-or-serialize-fn)
(s/def ::specified-by string?)
(s/def ::scalar-def (s/keys :req-un [::parse ::serialize]
:opt-un [::description]))
:opt-un [::description ::specified-by]))
(s/def ::description string?)

(s/def ::documentation (s/map-of keyword? string?))
Expand Down
71 changes: 40 additions & 31 deletions src/com/walmartlabs/lacinia/schema.clj
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@
[clojure.pprint :as pprint]
[com.walmartlabs.lacinia.selection :as selection])
(:import
(clojure.lang IObj PersistentQueue)
(java.io Writer)
(java.util.concurrent Executor ThreadPoolExecutor TimeUnit LinkedBlockingQueue ThreadFactory)))
(clojure.lang IObj PersistentQueue)
(java.io Writer)
(java.util.concurrent Executor ThreadPoolExecutor TimeUnit LinkedBlockingQueue ThreadFactory)))

;; When using Clojure 1.8, the dependency on clojure-future-spec must be included,
;; and this code will trigger
Expand Down Expand Up @@ -289,6 +289,13 @@
([message data]
(merge {:message message} data)))

(defn valid-url? [s]
(try
(let [uri (java.net.URI. s)]
(.toURL uri)
true)
(catch Exception _ false)))

;;-------------------------------------------------------------------------------
;; ## Validations

Expand Down Expand Up @@ -397,8 +404,10 @@
:var var?))
(s/def ::parse ::parse-or-serialize-fn)
(s/def ::serialize ::parse-or-serialize-fn)
(s/def ::specified-by valid-url?)
(s/def ::scalar (s/keys :opt-un [::description
::directives]
::directives
::specified-by]
:req-un [::parse
::serialize]))
(s/def ::scalars (s/map-of ::schema-key ::scalar))
Expand Down Expand Up @@ -614,7 +623,7 @@

(directives [_] compiled-directives))

(defrecord ^:private Scalar [category type-name description parse serialize directives compiled-directives]
(defrecord ^:private Scalar [category type-name description parse serialize directives compiled-directives specified-by]

selection/TypeDef

Expand Down Expand Up @@ -1924,9 +1933,9 @@
;; Note: using merge, not two calls to xfer-types, since want to allow
;; for overrides of the built-in scalars without a name conflict exception.
(let [merged-scalars (->> schema
:scalars
(merge default-scalar-transformers)
(map-vals #(assoc % :category :scalar)))
:scalars
(merge default-scalar-transformers)
(map-vals #(assoc % :category :scalar)))
executor (or (:executor options)
resolve/*callback-executor*
(default-executor))
Expand All @@ -1939,30 +1948,30 @@
:subscription subscription}
::executor executor
::options options}
(xfer-types merged-scalars :scalar)
(xfer-types (:enums schema) :enum)
(xfer-types (:unions schema) :union)
(xfer-types (:objects schema) :object)
(xfer-types (:interfaces schema) :interface)
(xfer-types (:input-objects schema) :input-object)
(add-root query :queries (:queries schema))
(add-root mutation :mutations (:mutations schema))
(add-root subscription :subscriptions (:subscriptions schema))
(apply-default-subscription-resolver subscription)
(as-> s
(map-vals #(compile-type % s) s))
(compile-directive-defs (:directive-defs schema))
(prepare-and-validate-interfaces)
(prepare-and-validate-objects :object)
(prepare-and-validate-objects :input-object)
(validate-directives-by-category :union)
(validate-directives-by-category :scalar)
validate-enum-directives
inject-null-collapsers
(xfer-types merged-scalars :scalar)
(xfer-types (:enums schema) :enum)
(xfer-types (:unions schema) :union)
(xfer-types (:objects schema) :object)
(xfer-types (:interfaces schema) :interface)
(xfer-types (:input-objects schema) :input-object)
(add-root query :queries (:queries schema))
(add-root mutation :mutations (:mutations schema))
(add-root subscription :subscriptions (:subscriptions schema))
(apply-default-subscription-resolver subscription)
(as-> s
(map-vals #(compile-type % s) s))
(compile-directive-defs (:directive-defs schema))
(prepare-and-validate-interfaces)
(prepare-and-validate-objects :object)
(prepare-and-validate-objects :input-object)
(validate-directives-by-category :union)
(validate-directives-by-category :scalar)
validate-enum-directives
inject-null-collapsers
;; Last so that schema is as close to final and verified state as possible
(prepare-field-resolvers options)
(prepare-field-streamers options)
map->CompiledSchema)))
(prepare-field-resolvers options)
(prepare-field-streamers options)
map->CompiledSchema)))

(defn default-field-resolver
"The default for the :default-field-resolver option, this uses the field name as the key into
Expand Down
20 changes: 20 additions & 0 deletions test/com/walmartlabs/introspection_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -1505,3 +1505,23 @@
:line 1}]
:message "Cannot query field `__type' on type `Query'."}]}
(execute schema q)))))

(def ^:private specified-by-url-query
"{
__type(name: \"DateTime\") {
name
kind
specifiedByUrl
}
}")

(deftest scalar-specified-by-url
(let [schema (schema/compile {:scalars {:DateTime {:parse identity
:serialize identity
:specified-by "https://scalars.graphql.org/andimarek/date-time.html"}}})]
(is (= {:data
{:__type
{:kind :SCALAR
:name "DateTime"
:specifiedByUrl "https://scalars.graphql.org/andimarek/date-time.html"}}}
(utils/execute schema specified-by-url-query)))))

0 comments on commit 5e1fca5

Please sign in to comment.