Clean up context and errors a little
M src/execution.lisp +10 -10
@@ 360,13 360,13 @@ 
     :finally (return (nreverse selection-set))))
 
 (defun execute (&optional operation-name initial-value)
-  (let ((*result* (make-hash-table :test #'equal))
-        (*errors* nil))
-    ;; TODO: We can't really validate yet
-    ;; (validate document)
-    (unless (document *context*)
-      (gql-error "We need a document to execute"))
-    (if *errors*
-        (setf (gethash "errors" *result*) *errors*)
-        (execute-request operation-name initial-value))
-    *result*))
+  (unless *context*
+    (gql-error "No context is set.  This is really bad."))
+  (unless (document *context*)
+    (gql-error "We need a document to execute"))
+  ;; TODO: We can't really validate yet
+  ;; (validate document)
+  (if *errors*
+      (setf (gethash "errors" *result*) *errors*)
+      (execute-request operation-name initial-value))
+  *result*)

          
M src/rules.lisp +5 -5
@@ 6,7 6,7 @@ 
     :for definition :in definitions
     :unless (or (eq (kind definition) 'operation-definition)
                 (eq (kind definition) 'fragment-definition))
-      :do (make-error "Each definition must be executable." definition)))
+      :do (push-error "Each definition must be executable." definition)))
 
 (defun operation-name-unique-p (definitions)
   ;; https://spec.graphql.org/draft/#sec-Operation-Name-Uniqueness

          
@@ 21,7 21,7 @@ 
        (loop
          :for v :being :each :hash-value :of operations
          :when (> (length v) 1)
-           :do (make-error "Each operation must have a unique name." v))))
+           :do (push-error "Each operation must have a unique name." v))))
 
 (defun single-anonymous-operation-definition-p (definitions)
   ;; https://spec.graphql.org/draft/#sec-Anonymous-Operation-Definitions

          
@@ 32,7 32,7 @@ 
     :when (null name-node)
       :do (push definition anonymous)
           (when (and (> (length definitions) 1) anonymous)
-            (make-error "An anonymous definition must be alone." definition)
+            (push-error "An anonymous definition must be alone." definition)
             (return))))
 
 (defun subscription-operation-valid-p ()

          
@@ 46,6 46,6 @@ 
                                              (make-hash-table)
                                              nil)
     :unless (= (hash-table-count grouped-field-set) 1)
-      :do (make-error "A subscription must have exactly one entry." subscription)
+      :do (push-error "A subscription must have exactly one entry." subscription)
     :when (introspection-field-p grouped-field-set)
-      :do (make-error "Root field must not begin with \"__\"  which is reserved by GraphQL introspection." subscription)))
+      :do (push-error "Root field must not begin with \"__\"  which is reserved by GraphQL introspection." subscription)))

          
M src/utils.lisp +20 -16
@@ 51,22 51,24 @@ 
   line
   column)
 
-(defun make-error (message nodes)
-  (let ((node-list (if (listp nodes) nodes (list nodes))))
-    (push (make-instance
-           'errors
-           :message message
-           :locations (mapcar
-                       (lambda (node)
-                         (with-slots (line column) (start-token (location node))
-                           (make-instance
-                            'error-location
-                            :line line
-                            :column column)))
-                       node-list)
-           :path nil
-           :extensions nil)
-          *errors*)))
+(defun location-errors (nodes)
+  (mapcar
+   (lambda (node)
+     (with-slots (line column) (start-token (location node))
+       (make-instance
+        'error-location
+        :line line
+        :column column)))
+   nodes))
+
+(defun push-error (message nodes)
+  (push (make-instance
+         'errors
+         :message message
+         :locations (location-errors (if (listp nodes) nodes (list nodes)))
+         :path nil ;; TODO: We need the path
+         :extensions nil) ;; TODO: Do we need extensions?
+        *errors*))
 
 (defun name-or-alias (field)
   (with-slots (alias name) field

          
@@ 96,6 98,8 @@ 
             (,d ,document)
             (,v (or ,variables ,(make-hash-table :test #'equal)))
             (,e ,execution-context)
+            (*result* (make-hash-table :test #'equal))
+            (*errors* nil)
             (*context* (make-instance 'context
                                       :schema ,s
                                       :document ,d

          
M t/execution-tests.lisp +13 -13
@@ 5,7 5,7 @@ 
     (let* ((definitions (gql::definitions
                          (build-schema "{ a { subfield1 } ...ExampleFragment } fragment ExampleFragment on Query { a { subfield2 } b }")))
            (query-type (gql::object :name "Query")))
-      (gql::with-context (:schema (gql::make-schema :query query-type :types (cdr definitions)))
+      (with-context (:schema (gql::make-schema :query query-type :types (cdr definitions)))
         (let* ((operation (find-if (lambda (x) (string= (gql::operation-type x) "Query")) definitions))
                (operation-type (gql::operation-type operation))
                (selection-set (gql::selection-set operation))

          
@@ 30,8 30,8 @@ 
   (testing "merge-selection-sets should merge multiple fields"
     (let* ((definitions (gql::definitions (build-schema (asdf:system-relative-pathname 'gql-tests #p"t/test-files/validation-schema.graphql"))))
            (query-type (find-if (lambda (x) (string= (gql::nameof x) "Query")) definitions)))
-      (gql::with-context (:schema (gql::make-schema :query query-type :types definitions)
-                          :document (build-schema "query { dog { name } dog { owner { name } } }"))
+      (with-context (:schema (gql::make-schema :query query-type :types definitions)
+                     :document (build-schema "query { dog { name } dog { owner { name } } }"))
         (gql::set-resolver "Human" "name" (lambda () "Bingo-bongo-pappa"))
         (gql::set-resolver "Dog" "name" (lambda () "Bingo-bongo"))
         (gql::set-resolver "Dog" "owner" (lambda () t))

          
@@ 47,8 47,8 @@ 
   (testing "A query should handle alias"
     (let* ((definitions (gql::definitions (build-schema (asdf:system-relative-pathname 'gql-tests #p"t/test-files/validation-schema.graphql"))))
            (query-type (find-if (lambda (x) (string= (gql::nameof x) "Query")) definitions)))
-      (gql::with-context (:schema (gql::make-schema :query query-type :types definitions)
-                          :document (build-schema "query { dog { name owner { name: nameAlias } } }"))
+      (with-context (:schema (gql::make-schema :query query-type :types definitions)
+                     :document (build-schema "query { dog { name owner { name: nameAlias } } }"))
         (gql::set-resolver "Human" "name" (lambda () "Bingo-bongo-pappa"))
         (gql::set-resolver "Dog" "name" (lambda () "Bingo-bongo"))
         (gql::set-resolver "Dog" "owner" (lambda () t))

          
@@ 64,8 64,8 @@ 
   (testing "A query should handle variables and arguments"
     (let* ((definitions (gql::definitions (build-schema (asdf:system-relative-pathname 'gql-tests #p"t/test-files/validation-schema.graphql"))))
            (query-type (find-if (lambda (x) (string= (gql::nameof x) "Query")) definitions)))
-      (gql::with-context (:schema (gql::make-schema :query query-type :types definitions)
-                          :document (build-schema "query x($sit: String) { dog { doesKnowCommand(dogCommand: $sit) } }"))
+      (with-context (:schema (gql::make-schema :query query-type :types definitions)
+                     :document (build-schema "query x($sit: String) { dog { doesKnowCommand(dogCommand: $sit) } }"))
         (setf (gethash "sit" (gql::variables gql::*context*)) "SIT")
         (gql::set-resolver "Dog" "name" (lambda () "Bingo-bongo"))
         (gql::set-resolver "Dog" "doesKnowCommand"

          
@@ 109,8 109,8 @@ 
   (testing "Using resolvers that access the object from the 'db'"
     (let* ((definitions (gql::definitions (build-schema (asdf:system-relative-pathname 'gql-tests #p"t/test-files/validation-schema.graphql"))))
            (query-type (find-if (lambda (x) (string= (gql::nameof x) "Query")) definitions)))
-      (gql::with-context (:schema (gql::make-schema :query query-type :types definitions)
-                          :document (build-schema "query { dog { name } }"))
+      (with-context (:schema (gql::make-schema :query query-type :types definitions)
+                     :document (build-schema "query { dog { name } }"))
         (gql::defclass* dog name owner)
         (gql::set-resolver "Dog" "name"
                            (lambda () (name (gql::object-value (gql::execution-context gql::*context*)))))

          
@@ 131,7 131,7 @@ 
   (testing "A query should handle variables and arguments"
     (let*  ((definitions (gql::definitions (build-schema (asdf:system-relative-pathname 'gql-tests #p"t/test-files/validation-schema.graphql"))))
             (query-type (find-if (lambda (x) (string= (gql::nameof x) "Query")) definitions)))
-      (gql::with-context (:schema (gql::make-schema :query query-type :types definitions))
+      (with-context (:schema (gql::make-schema :query query-type :types definitions))
         (gql::defclass* dog name does-know-command)
         (setf (gethash "sit" (gql::variables gql::*context*)) "SIT")
 

          
@@ 188,7 188,7 @@ 
     (let* ((doggo (make-instance 'dog :name "Bingo-Bongo" :type-name "Dog"))
            (definitions (gql::definitions (build-schema (asdf:system-relative-pathname 'gql-tests #p"t/test-files/validation-schema.graphql"))))
            (query-type (find-if (lambda (x) (string= (gql::nameof x) "Query")) definitions)))
-      (gql::with-context (:schema (gql::make-schema :query query-type :types definitions))
+      (with-context (:schema (gql::make-schema :query query-type :types definitions))
         ;; We want to know if we did get the actual same reference.
         (ok (eq (gql::resolve-abstract-type (gethash "CatOrDog" (gql::type-map (gql::schema gql::*context*))) doggo)
                 (gethash "Dog" (gql::type-map (gql::schema gql::*context*)))))

          
@@ 279,8 279,8 @@ 
                                                  :resolver (lambda () (nickname (gql::object-value (gql::execution-context gql::*context*)))))))))
 
       (flet ((doggo-test (query)
-               (gql::with-context (:schema (gql::make-schema :query query-type :types (list dog-type human-type cat-type pet-interface))
-                                   :document (build-schema query))
+               (with-context (:schema (gql::make-schema :query query-type :types (list dog-type human-type cat-type pet-interface))
+                              :document (build-schema query))
                  (let* ((res (gql::execute nil nil)))
                    (format nil "~a" (cl-json:encode-json-to-string res))))))
 

          
M t/introspection-tests.lisp +4 -4
@@ 66,10 66,10 @@ 
                                                                                 :pets '())))))))
 
       (flet ((doggo-test (query)
-               (gql::with-context (:schema (gql::make-schema :query query-type :types (list dog-type human-type))
-                                   :document (build-schema query))
-                 (let* ((res (gql::execute nil nil)))
-                   (format nil "~a" (cl-json:encode-json-to-string res))))))
+               (with-context
+                   (:schema (gql::make-schema :query query-type :types (list dog-type human-type))
+                    :document (build-schema query))
+                 (format nil "~a" (cl-json:encode-json-to-string (gql::execute nil nil))))))
 
         (ok (string=
              (doggo-test "query { dog { __typename name owner { name } } }")

          
M t/type-system-tests.lisp +4 -4
@@ 128,7 128,7 @@ scalar Url
   (testing "scalar"
     (let* ((definitions (gql::definitions (build-schema (asdf:system-relative-pathname 'gql-tests #p"t/test-files/validation-schema.graphql"))))
            (query-type (find-if (lambda (x) (string= (gql::nameof x) "Query")) definitions)))
-      (gql::with-context (:schema (gql::make-schema :query query-type :types definitions))
+      (with-context (:schema (gql::make-schema :query query-type :types definitions))
         (let ((dog (gethash "Dog" (gql::type-map (gql::schema gql::*context*)))))
           (ok (gql::input-type-p (gql::ty (gethash "name" (gql::fields dog)))))
           (ok (gql::input-type-p (gql::ty (gethash "nickname" (gql::fields dog)))))

          
@@ 137,7 137,7 @@ scalar Url
   (testing "union"
     (let* ((definitions (gql::definitions (build-schema (asdf:system-relative-pathname 'gql-tests #p"t/test-files/validation-schema.graphql"))))
            (query-type (find-if (lambda (x) (string= (gql::nameof x) "Query")) definitions)))
-      (gql::with-context (:schema (gql::make-schema :query query-type :types definitions))
+      (with-context (:schema (gql::make-schema :query query-type :types definitions))
         (let ((human-or-alien (gethash "HumanOrAlien" (gql::type-map (gql::schema gql::*context*)))))
           (ng (gql::input-type-p (gethash "Human" (gql::union-members human-or-alien))))
           (ng (gql::input-type-p (gethash "Alien" (gql::union-members human-or-alien))))

          
@@ 146,7 146,7 @@ scalar Url
   (testing "object"
     (let* ((definitions (gql::definitions (build-schema (asdf:system-relative-pathname 'gql-tests #p"t/test-files/validation-schema.graphql"))))
            (query-type (find-if (lambda (x) (string= (gql::nameof x) "Query")) definitions)))
-      (gql::with-context (:schema (gql::make-schema :query query-type :types definitions))
+      (with-context (:schema (gql::make-schema :query query-type :types definitions))
         (let ((dog-or-human (gethash "DogOrHuman" (gql::type-map (gql::schema gql::*context*)))))
           (ng (gql::input-type-p (gethash "Dog" (gql::union-members dog-or-human))))
           (ng (gql::input-type-p (gethash "Human" (gql::union-members dog-or-human))))

          
@@ 155,7 155,7 @@ scalar Url
   (testing "interface"
     (let* ((definitions (gql::definitions (build-schema (asdf:system-relative-pathname 'gql-tests #p"t/test-files/validation-schema.graphql"))))
            (query-type (find-if (lambda (x) (string= (gql::nameof x) "Query")) definitions)))
-      (gql::with-context (:schema (gql::make-schema :query query-type :types definitions))
+      (with-context (:schema (gql::make-schema :query query-type :types definitions))
         (let ((cat (gethash "Cat" (gql::type-map (gql::schema gql::*context*)))))
           (ng (gql::input-type-p (gethash "Pet" (gql::interfaces cat))))
           (ok (gql::output-type-p (gethash "Pet" (gql::interfaces cat)))))))))