项目作者: oliyh

项目描述 :
Generators for GraphQL
高级语言: Clojure
项目地址: git://github.com/oliyh/lacinia-gen.git
创建时间: 2018-03-01T16:53:12Z
项目社区:https://github.com/oliyh/lacinia-gen

开源协议:

下载


lacinia-gen

lacinia-gen lets you generate GraphQL responses using your lacinia schema
and GraphQL queries, allowing you to make your tests more rigorous in both Clojure and Clojurescript.

Clojars Project

Usage

There are two main ways to use lacinia-gen:

  • Full graph generates the entire graph from any entry point
  • Query result generates a response for a particular query

Full graph

You can create a generator for a full graph from any root by using the generator function in
lacinia-gen.core. This resolves all reachable nodes in the graph up to the desired recursion depth.

  1. (require '[lacinia-gen.core :as lgen])
  2. (require '[clojure.test.check.generators :as g])
  3. (let [schema {:enums {:position {:values [:goalkeeper :defence :attack]}}
  4. :objects {:team {:fields {:wins {:type 'Int}
  5. :losses {:type 'Int}
  6. :players {:type '(list :player)}}}
  7. :player {:fields {:name {:type 'String}
  8. :age {:type 'Int}
  9. :position {:type :position}}}}}]
  10. (let [gen (lgen/generator schema)]
  11. (g/sample (gen :position) 5)
  12. ;; => (:defence :goalkeeper :defence :goalkeeper :goalkeeper)
  13. (g/sample (gen :player) 5)
  14. ;; => ({:name "", :age 0, :position :attack}
  15. {:name "", :age 0, :position :attack}
  16. {:name "", :age 1, :position :attack}
  17. {:name "–m", :age -2, :position :defence}
  18. {:name "¤", :age 4, :position :defence})
  19. (g/sample (gen :team) 5)
  20. ;; => ({:wins 0, :losses 0, :players ()}
  21. {:wins 1,
  22. :losses 1,
  23. :players ({:name "", :age -1, :position :defence})}
  24. {:wins 1,
  25. :losses 2,
  26. :players
  27. ({:name "", :age 1, :position :attack}
  28. {:name "q", :age -2, :position :attack})}
  29. {:wins -3, :losses 1, :players ()}
  30. {:wins 0,
  31. :losses -3,
  32. :players
  33. ({:name "‘ßéÅ", :age 3, :position :attack}
  34. {:name "", :age -4, :position :defence})})))

It supports recursive graphs, so the following works too:

  1. (let [schema {:objects {:team {:fields {:name {:type 'String}
  2. :players {:type '(list :player)}}}
  3. :player {:fields {:name {:type 'String}
  4. :team {:type :team}}}}}]
  5. (let [gen (lgen/generator schema)]
  6. (g/sample (gen :team) 5)))
  7. ;; => {:name "ö–",
  8. :players
  9. ({:name "³2",
  10. :team
  11. {:name "ºN",
  12. :players
  13. ({:name "Ïâ¦", :team {:name "¤¼J"}}
  14. {:name "o", :team {:name "æ‚8‹"}}
  15. {:name "/ç", :team {:name "ãL"}}
  16. {:name "éíª6", :team {:name "v‡"}})}}

If you want to limit the depth to which certain objects recurse, you can do so with the following option:

  1. (lgen/generator schema {:depth {:team 0}})

This will ensure that :team only appears once in the graph; the team will have players, but it prevents the players from having a team.
The default value for all objects is 1, meaning each will recur once (a team will have players which have a team which has players, but no further).
You can set any integer value you wish.

If you want to limit the number of items in lists, you can do so with the following option:

  1. (lgen/generator schema {:width {:player 2}})

This will ensure that lists of :player will have a maximum size of 2.

Query result

If you have a GraphQL query and wish to generate data for its result, you can use lacinia-gen.query.

  1. (require '[lacinia-gen.query :as query])
  2. (def schema '{:enums {:position {:values [:goalkeeper :defence :attack]}}
  3. :objects {:team {:fields {:wins {:type Int}
  4. :losses {:type Int}
  5. :players {:type (list :player)}}}
  6. :player {:fields {:name {:type String}
  7. :age {:type Int}
  8. :position {:type :position}}}}
  9. :queries {:teams {:type (list :team)
  10. :resolve :resolve-teams}}})
  11. (let [f (query/generate-fn schema {})]
  12. (f "query { teams { wins players { name } } }" {}))
  13. ;; => {:data
  14. {:teams
  15. ({:wins 0, :players ()}
  16. {:wins 0, :players ({:name ""})}
  17. {:wins 1, :players ()}
  18. {:wins 0, :players ({:name "÷ "} {:name "¢"})}
  19. {:wins 1, :players ()})}}

Currently the queries are interpreted by Lacinia and as such require the JVM. This means
generate-fn cannot be used from Clojurescript. The two macros generate-query and
generate-query* may be used in Clojurescript and will evaluate to the generated result
of the query.

  1. (ns my.test
  2. (:require-macros [lacinia-gen.query :refer [generate-data*]]))
  3. (def schema '{:objects {:team {:fields {:wins {:type Int}
  4. :losses {:type Int}}}}
  5. :queries {:teams {:type (list :team)
  6. :resolve :resolve-teams}}})
  7. (def query "query { teams { wins } }")
  8. (def data (generate-data* schema query {} {}))
  9. data
  10. ;; => {:data
  11. {:teams
  12. ({:wins 0}
  13. {:wins 0}
  14. {:wins 0)}
  15. {:wins -3}
  16. {:wins 0})}

Custom scalars

If your schema contains custom scalars you will need to
provide generators for them. You can do so in the following way:

  1. (let [schema {:scalars {:Custom {:parse :parse-custom
  2. :serialize :serialize-custom}}
  3. :objects {:obj-with-custom
  4. {:fields
  5. {:custom {:type :Custom}
  6. :custom-list {:type '(list :Custom)}}}}}]
  7. (let [gen (lgen/generator schema {:scalars {:Custom gen/int}})]
  8. (g/sample (gen :obj-with-custom) 10)))
  9. ;; => {:custom 23
  10. :custom-list (-1 4 16)}

Development

CircleCI

License

Copyright © 2018 oliyh

Distributed under the Eclipse Public License either version 1.0 or (at
your option) any later version.