Introduce make-resolvers

Simple and naive approach for now.  Doesn't do gensyms, so beware.
M example/example2.lisp +14 -24
@@ 34,22 34,18 @@ 
                      :type-name "Dog")))))
 
 (defvar *query-resolvers*
-  (let ((ht (make-hash-table :test #'equal)))
-    (setf (gethash "dog" ht)
-          (lambda (arg) (declare (ignorable arg)) *doggo*))
-    ht))
+  (make-resolvers
+    ("dog" . (constantly *doggo*))))
 
 (defvar *dog-resolvers*
-  (let ((ht (make-hash-table :test #'equal)))
-    (setf (gethash "name" ht) (lambda (dog) (name dog)))
-    (setf (gethash "owner" ht) (lambda (dog) (owner dog)))
-    ht))
+  (make-resolvers
+    ("name"  . 'name)
+    ("owner" . 'owner)))
 
 (defvar *human-resolvers*
-  (let ((ht (make-hash-table :test #'equal)))
-    (setf (gethash "name" ht) (lambda (human) (name human)))
-    (setf (gethash "pets" ht) (lambda (human) (pets human)))
-    ht))
+  (make-resolvers
+    ("name" . 'name)
+    ("pets" . 'pets)))
 
 (defun example2 (query)
   (with-schema (build-schema (asdf:system-relative-pathname 'gql-tests #p"t/test-files/validation-schema.graphql"))

          
@@ 57,16 53,10 @@ 
                  (build-schema query) nil (make-hash-table :test #'equal) nil)))
       (format t "~%~a" (cl-json:encode-json-to-string res)))))
 
-(let ((*resolvers* (make-hash-table :test #'equal)))
-  (setf (gethash "Query" *resolvers*) *query-resolvers*)
-  (setf (gethash "Dog" *resolvers*) *dog-resolvers*)
-  (setf (gethash "Human" *resolvers*) *human-resolvers*)
-  (example2 "query { dog { name owner { name pets { name } } } }"))
-
-(let ((*resolvers* (make-hash-table :test #'equal)))
-  (setf (gethash "Query" *resolvers*) *query-resolvers*)
-  (setf (gethash "Dog" *resolvers*) *dog-resolvers*)
-  (setf (gethash "Human" *resolvers*) *human-resolvers*)
+(let ((*resolvers*
+        (make-resolvers
+          ("Query"    . *query-resolvers*)
+          ("Dog"      . *dog-resolvers*)
+          ("Human"    . *human-resolvers*))))
+  (example2 "query { dog { name owner { name pets { name } } } }")
   (example2 "query { dog { name owner: wingle { name pets: dogs { name } } } }"))
-
-

          
M example/package.lisp +0 -1
@@ 1,3 1,2 @@ 
-
 (defpackage :gql-example
   (:use :cl :gql))

          
M src/package.lisp +2 -1
@@ 14,4 14,5 @@ 
    #:bool
    #:true
    #:false
-   #:gql-object))
+   #:gql-object
+   #:make-resolvers))

          
M src/utils.lisp +8 -0
@@ 97,3 97,11 @@ documents."
              (fields (gethash (nameof object-type) *all-types*)))))
 
 (defclass* gql-object type-name)
+
+(defmacro make-resolvers (&body body)
+  `(let ((ht (make-hash-table :test #'equal)))
+     ,@(mapcar
+        (lambda (resolver)
+          `(setf (gethash ,(car resolver) ht) ,(cdr resolver)))
+        body)
+     ht))

          
M t/execution-tests.lisp +40 -46
@@ 251,59 251,53 @@ 
     (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")))))
-
-    (let* ((query-resolvers
-             (let ((ht (make-hash-table :test #'equal)))
-               (setf (gethash "dog" ht)
-                     (lambda (arg) (declare (ignorable arg)) *doggo*))
-               ht))
+    (let* ((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")))))
+           (query-resolvers
+             (make-resolvers
+               ("dog"      . (constantly doggo))))
 
            (dog-resolvers
-             (let ((ht (make-hash-table :test #'equal)))
-               (setf (gethash "name" ht) (lambda (dog) (name dog)))
-               (setf (gethash "nickname" ht) (lambda (dog) (nickname dog)))
-               (setf (gethash "owner" ht) (lambda (dog) (owner dog)))
-               ht))
+             (make-resolvers
+               ("name"     . 'name)
+               ("nickname" . 'nickname)
+               ("owner"    . 'owner)))
 
            (cat-resolvers
-             (let ((ht (make-hash-table :test #'equal)))
-               (setf (gethash "name" ht) (lambda (cat) (name cat)))
-               (setf (gethash "nickname" ht) (lambda (cat) (nickname cat)))
-               (setf (gethash "owner" ht) (lambda (cat) (owner cat)))
-               ht))
+             (make-resolvers
+               ("name"     . 'name)
+               ("nickname" . 'nickname)
+               ("owner"    . 'owner)))
 
            (human-resolvers
-             (let ((ht (make-hash-table :test #'equal)))
-               (setf (gethash "name" ht) (lambda (human) (name human)))
-               (setf (gethash "pets" ht) (lambda (human) (pets human)))
-               ht))
+             (make-resolvers
+               ("name"     . 'name)
+               ("pets"     . 'pets)))
+
            (*resolvers*
-             (let ((ht (make-hash-table :test #'equal)))
-               (setf (gethash "Query" ht) query-resolvers)
-               (setf (gethash "Dog" ht) dog-resolvers)
-               (setf (gethash "Cat" ht) cat-resolvers)
-               (setf (gethash "Human" ht) human-resolvers)
-               ht)))
+             (make-resolvers
+               ("Query"    . query-resolvers)
+               ("Dog"      . dog-resolvers)
+               ("Cat"      . cat-resolvers)
+               ("Human"    . human-resolvers))))
 
       (flet ((doggo-test (query)
                (with-schema (build-schema (asdf:system-relative-pathname 'gql-tests #p"t/test-files/validation-schema.graphql"))

          
M wiki/examples/example2.md +22 -33
@@ 61,33 61,30 @@ Let's see our "database":
                      :type-name "Dog")))))
 ```
 
-Next up are the resolvers.  These are pretty simple to make, but has a bit ugly syntax for now:
+Next up are the resolvers.  These are pretty simple to make, and uses a simple
+helper macro to aid with getting the syntax right.
 
 ```lisp
 (defvar *query-resolvers*
-  (let ((ht (make-hash-table :test #'equal)))
-    (setf (gethash "dog" ht)
-          (lambda (arg) (declare (ignorable arg)) *doggo*))
-    ht))
+  (make-resolvers
+    ("dog" . (constantly *doggo*))))
 
 (defvar *dog-resolvers*
-  (let ((ht (make-hash-table :test #'equal)))
-    (setf (gethash "name" ht) (lambda (dog) (name dog)))
-    (setf (gethash "owner" ht) (lambda (dog) (owner dog)))
-    ht))
+  (make-resolvers
+    ("name"  . 'name)
+    ("owner" . 'owner)))
 
 (defvar *human-resolvers*
-  (let ((ht (make-hash-table :test #'equal)))
-    (setf (gethash "name" ht) (lambda (human) (name human)))
-    (setf (gethash "pets" ht) (lambda (human) (pets human)))
-    ht))
+  (make-resolvers
+    ("name" . 'name)
+    ("pets" . 'pets)))
 ```
 
 `*query-resolvers*` has just a simple function inside, which returns object from
 the "database".  This is typically where the first calls to the database is
-made. `*dog-resolvers*` contains lambdas wrapping getters from the object as
-they are defined through clos.  We wrap it in a lambda so that `gql` can call
-the function for us.  The same is true for `*human-resolvers*`.
+made. `*dog-resolvers*` contains getters from the object as they are defined
+through clos.  `gql` can call the function for us.  The same is true for
+`*human-resolvers*`.
 
 At last, we can do the request.  We need to parse the schema, then make the
 request.  We don't need any variable-values now, because we still keep the

          
@@ 101,14 98,16 @@ queries simple.  Our function looks like
       (format t "~a" (cl-json:encode-json-to-string res)))))
 ```
 
-Now we just bind the resolvers to the exported `*resolvers*` symbol and run our query:
+Now we just bind the resolvers to the exported `*resolvers*` symbol and run our queries:
 
 ```lisp
-(let ((*resolvers* (make-hash-table :test #'equal)))
-  (setf (gethash "Query" *resolvers*) *query-resolvers*)
-  (setf (gethash "Dog" *resolvers*) *dog-resolvers*)
-  (setf (gethash "Human" *resolvers*) *human-resolvers*)
-  (example2 "query { dog { name owner { name pets { name } } } }"))
+(let ((*resolvers*
+        (make-resolvers
+          ("Query"    . *query-resolvers*)
+          ("Dog"      . *dog-resolvers*)
+          ("Human"    . *human-resolvers*))))
+  (example2 "query { dog { name owner { name pets { name } } } }")
+  (example2 "query { dog { name owner: wingle { name pets: dogs { name } } } }"))
 ```
 
 This yields:

          
@@ 135,17 134,7 @@ This yields:
 }
 ```
 
-We can add aliases to our queries, so that we can be super agile(tm) in the front-end:
-
-```lisp
-(let ((*resolvers* (make-hash-table :test #'equal)))
-  (setf (gethash "Query" *resolvers*) *query-resolvers*)
-  (setf (gethash "Dog" *resolvers*) *dog-resolvers*)
-  (setf (gethash "Human" *resolvers*) *human-resolvers*)
-  (example2 "query { dog { name owner: wingle { name pets: dogs { name } } } }"))
-```
-
-Now we get:
+The second query adds a few aliases, so that we can be super agile(tm):
 
 ```json
 {