Resolve union members

Fixes: https://todo.sr.ht/~theo/gql/29
2 files changed, 54 insertions(+), 6 deletions(-)

M src/execution.lisp
M t/execution-tests.lisp
M src/execution.lisp +8 -6
@@ 259,13 259,15 @@ 
 
 (defun resolve-abstract-type (abstract-type object-value)
   ;; TODO: https://spec.graphql.org/draft/#ResolveAbstractType()
-  ;; TODO: #29
   (check-type object-value gql-object)
-  (etypecase abstract-type
-    (interface-type-definition
-     ;; TODO: Should this error handle somehow?
-     (gethash (type-name object-value) *all-types*))
-    (union-type-definition nil)))
+  (let* ((type-name (type-name object-value))
+         (object-definition (gethash type-name *all-types*)))
+    (etypecase abstract-type
+      (interface-type-definition object-definition)
+      (union-type-definition
+       (let ((union-member
+               (find type-name (union-members abstract-type) :key #'nameof :test #'string=)))
+         (gethash (nameof union-member) *all-types*))))))
 
 (defun execute-field (object-type object-value field-type fields variable-values)
   ;; TODO: https://spec.graphql.org/draft/#sec-Executing-Fields

          
M t/execution-tests.lisp +46 -0
@@ 216,6 216,52 @@ 
                (command (gethash "doesKnowCommand" dog)))
           (ok (string= command "false")))))))
 
+(deftest abstract-type-resolvers
+  (testing "Getting object-type-definition from union or interface"
+    (defclass pet (gql-object)
+      ((name :initarg :name :accessor name)))
+
+    (defclass dog (pet)
+      ((owner :initarg :owner :accessor owner)
+       (nickname :initarg :nickname :accessor nickname)))
+
+    (defclass cat (pet)
+      ((nickname :initarg :nickname :accessor nickname)))
+
+    (defclass sentient (gql-object)
+      ((name :initarg :name :accessor name)))
+
+    (defclass human (sentient)
+      ((pets :initarg :pets :accessor pets)))
+
+    (defparameter *doggo*
+      (make-instance
+       'dog
+       :name "Bingo-Bongo"
+       :type-name "Dog"
+       :nickname "Hund!"
+       :owner (make-instance
+               'human
+               :name "Wingle Wangle"
+               :type-name "Human"
+               :pets `(,(make-instance
+                         'dog
+                         :name "Bingo-Bongo"
+                         :nickname "Hund!"
+                         :type-name "Dog")
+                       ,(make-instance
+                         'cat
+                         :name "Bango-Wango"
+                         :nickname "Mjausig"
+                         :type-name "Cat")))))
+
+    (with-schema (build-schema (asdf:system-relative-pathname 'gql-tests #p"t/test-files/validation-schema.graphql"))
+      ;; We want to know if we did get the actual same reference.
+      (ok (eq (gql::resolve-abstract-type (gethash "CatOrDog" gql::*all-types*) *doggo*)
+              (gethash "Dog" gql::*all-types*)))
+      (ok (eq (gql::resolve-abstract-type (gethash "Pet" gql::*all-types*) *doggo*)
+              (gethash "Dog" gql::*all-types*))))))
+
 (deftest doggo-test
   (testing "Doggo-testing"
     (defclass pet (gql-object)