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
{