• Stars
    star
    69
  • Rank 452,630 (Top 9 %)
  • Language
    Clojure
  • Created almost 7 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Generators for GraphQL

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.

(require '[lacinia-gen.core :as lgen])
(require '[clojure.test.check.generators :as g])

(let [schema {:enums {:position {:values [:goalkeeper :defence :attack]}}
              :objects {:team {:fields {:wins {:type 'Int}
                                        :losses {:type 'Int}
                                        :players {:type '(list :player)}}}
                        :player {:fields {:name {:type 'String}
                                          :age {:type 'Int}
                                          :position {:type :position}}}}}]

  (let [gen (lgen/generator schema)]

    (g/sample (gen :position) 5)
    ;; => (:defence :goalkeeper :defence :goalkeeper :goalkeeper)

    (g/sample (gen :player) 5)
    ;; => ({:name "", :age 0, :position :attack}
           {:name "", :age 0, :position :attack}
           {:name "", :age 1, :position :attack}
           {:name "�m", :age -2, :position :defence}
           {:name "¤", :age 4, :position :defence})

    (g/sample (gen :team) 5)
    ;; => ({:wins 0, :losses 0, :players ()}
           {:wins 1,
            :losses 1,
            :players ({:name "", :age -1, :position :defence})}
           {:wins 1,
            :losses 2,
            :players
            ({:name "", :age 1, :position :attack}
             {:name "q", :age -2, :position :attack})}
           {:wins -3, :losses 1, :players ()}
           {:wins 0,
            :losses -3,
            :players
            ({:name "�ßéÅ", :age 3, :position :attack}
             {:name "", :age -4, :position :defence})})))

It supports recursive graphs, so the following works too:

(let [schema {:objects {:team {:fields {:name {:type 'String}
                                        :players {:type '(list :player)}}}
                        :player {:fields {:name {:type 'String}
                                          :team {:type :team}}}}}]

    (let [gen (lgen/generator schema)]
      (g/sample (gen :team) 5)))

;; => {:name "�ö�",
       :players
       ({:name "³2",
         :team
         {:name "º��N",
          :players
          ({:name "Ïâ¦", :team {:name "¤¼J"}}
           {:name "o", :team {:name "æ�8�"}}
           {:name "", :team {:name "ãL"}}
           {: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:

(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:

(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.

(require '[lacinia-gen.query :as query])

(def schema '{:enums {:position {:values [:goalkeeper :defence :attack]}}
              :objects {:team {:fields {:wins {:type Int}
                                        :losses {:type Int}
                                        :players {:type (list :player)}}}
                        :player {:fields {:name {:type String}
                                          :age {:type Int}
                                          :position {:type :position}}}}
              :queries {:teams {:type (list :team)
                                :resolve :resolve-teams}}})

(let [f (query/generate-fn schema {})]
    (f "query { teams { wins players { name } } }" {}))

;; => {:data
       {:teams
        ({:wins 0, :players ()}
         {:wins 0, :players ({:name ""})}
         {:wins 1, :players ()}
         {:wins 0, :players ({:name "÷ "} {:name "�¢�"})}
         {: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.

(ns my.test
  (:require-macros [lacinia-gen.query :refer [generate-data*]]))

(def schema '{:objects {:team {:fields {:wins {:type Int}
                                        :losses {:type Int}}}}
              :queries {:teams {:type (list :team)
                                :resolve :resolve-teams}}})

(def query "query { teams { wins } }")

(def data (generate-data* schema query {} {}))

data
;; => {:data
       {:teams
        ({:wins 0}
         {:wins 0}
         {:wins 0)}
         {:wins -3}
         {: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:

(let [schema {:scalars {:Custom {:parse :parse-custom
                                 :serialize :serialize-custom}}
              :objects {:obj-with-custom
                        {:fields
                         {:custom {:type :Custom}
                          :custom-list {:type '(list :Custom)}}}}}]

  (let [gen (lgen/generator schema {:scalars {:Custom gen/int}})]
    (g/sample (gen :obj-with-custom) 10)))

;; => {:custom 23
       :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.

More Repositories

1

martian

The HTTP abstraction library for Clojure/script, supporting OpenAPI, Swagger, Schema, re-frame and more
Clojure
470
star
2

re-graph

A graphql client for clojurescript and clojure
Clojure
447
star
3

superlifter

A DataLoader for Clojure/script
Clojure
158
star
4

re-learn

A library for integrating tutorials into your re-frame/reagent application
Clojure
138
star
5

pedestal-api

Easily build APIs in Pedestal using Schema and Swagger
Clojure
106
star
6

kamera

UI testing via image comparison and devcards
Clojure
86
star
7

re-jump.el

emacs navigation for re-frame projects
Emacs Lisp
69
star
8

locksmith

Want to use GraphQL with Clojure/script but don't want keBab or snake_keys everywhere? Use locksmith to change all the keys!
Clojure
61
star
9

slacky

Memes as a Slack Service
Clojure
33
star
10

angel-interceptor

Express relations between Pedestal interceptors and decouple scope from execution order
Clojure
28
star
11

doo-chrome-devprotocol

A runner for doo which runs tests in Chrome, using the Chrome Dev Protocol with no need for karma or npm.
Clojure
27
star
12

carmine-streams

Utility functions for working with Redis streams in carmine
Clojure
26
star
13

fixa

Better test fixtures for clojure
Clojure
26
star
14

oxbow

A Server Sent Events (SSE) client for Clojurescript based on js/fetch
Clojure
24
star
15

spa-skeleton

A skeleton project for a ClojureScript Single Page Application backed by a Swagger API
Clojure
21
star
16

re-partee

How I build Clojurescript apps
Clojure
15
star
17

carve.el

Emacs plugin for borkdude/carve
Emacs Lisp
9
star
18

alrightee

Tee for re-frame
Clojure
7
star
19

learning-clojure

Learning materials for Clojure
Clojure
5
star
20

tinybeans-archive

Create an archive of a tinybeans journal
Clojure
4
star
21

cljockwork

A REST API for cron4j, written in Clojure
Clojure
4
star
22

stardev-feedback

Capturing feedback for https://stardev.io
3
star
23

haproxy-cert-jwt

A Lua extension for HAProxy to turn an SSL client certificate into a JWT for the backend
Lua
2
star
24

one-route

A Ring webserver with one route
HTML
2
star
25

slacky-bot

All the memes for Slack
Clojure
2
star
26

cljs-webapp-from-scratch

Clojure
2
star
27

ingred

Search recipes by ingredient - a REST api written in Clojure with data scraped from the BBC
Clojure
2
star
28

sunshine

Clojure
2
star
29

fast-feedback

A presentation giving guidance on how to optimise your feedback loop and improve efficiency
HTML
1
star
30

a-taste-of-clojure

A talk to introduce (Java) developers to Clojure
JavaScript
1
star
31

sanakone

Learn Finnish
Clojure
1
star
32

masvn

Subversion integration for emacs based on dsvn and inspired by magit
Emacs Lisp
1
star