# HG changeset patch # User Theodor Thornhill # Date 1638953693 -3600 # Wed Dec 08 09:54:53 2021 +0100 # Node ID 390850519253f2345cfa9f9bbe97a7e3ec7adb52 # Parent f51db9fda8ce807d84898e7aa277246b74f836f0 Introduce make-resolvers Simple and naive approach for now. Doesn't do gensyms, so beware. diff --git a/example/example2.lisp b/example/example2.lisp --- a/example/example2.lisp +++ b/example/example2.lisp @@ -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 } } } }")) - - diff --git a/example/package.lisp b/example/package.lisp --- a/example/package.lisp +++ b/example/package.lisp @@ -1,3 +1,2 @@ - (defpackage :gql-example (:use :cl :gql)) diff --git a/src/package.lisp b/src/package.lisp --- a/src/package.lisp +++ b/src/package.lisp @@ -14,4 +14,5 @@ #:bool #:true #:false - #:gql-object)) + #:gql-object + #:make-resolvers)) diff --git a/src/utils.lisp b/src/utils.lisp --- a/src/utils.lisp +++ b/src/utils.lisp @@ -97,3 +97,11 @@ (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)) diff --git a/t/execution-tests.lisp b/t/execution-tests.lisp --- a/t/execution-tests.lisp +++ b/t/execution-tests.lisp @@ -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")) diff --git a/wiki/examples/example2.md b/wiki/examples/example2.md --- a/wiki/examples/example2.md +++ b/wiki/examples/example2.md @@ -61,33 +61,30 @@ :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 @@ (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 @@ } ``` -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 {