Skip to content

Instantly share code, notes, and snippets.

@danielneal
Last active May 23, 2017 19:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danielneal/ae3a1b6ddfc52393dd18c859464a6ec3 to your computer and use it in GitHub Desktop.
Save danielneal/ae3a1b6ddfc52393dd18c859464a6ec3 to your computer and use it in GitHub Desktop.
(ns app.graphql
(:require [om.next :as om]
[clojure.string :as str]
[clojure.set :as set]))
(defn graphql-type [v]
(cond
(string? v) "String"
(int? v) "Int"
(float? v) "Float"
(boolean? v) "Boolean"
:else "String"))
(def graphql-symbols
{::arg-brace-left "("
::arg-brace-right ")"
::arg-list-separator ","
::arg-separator ":"
::arg-signifier "$"
::field-brace-left "{"
::field-brace-right "}"
::separator " "
::query-signifier "query "
::union-signifier "... on"})
(defn params->graphql [params]
(let [variables (set (for [[k v] params]
{:name (name k)
:unique-name (gensym (name k))
:type (graphql-type v)
:value v}))]
{:query [::arg-brace-left
(->> (for [{:keys [name unique-name]} variables]
[name ::arg-separator ::arg-signifier unique-name])
(interpose ::arg-list-separator))
::arg-brace-right]
:variables variables}))
(defmulti node->graphql :type)
(defmethod node->graphql :prop
[node]
(let [{:keys [dispatch-key params]} node
graphql-params (some-> params params->graphql)]
{:query [(name dispatch-key) (:query graphql-params)]
:variables (:variables graphql-params)}))
(defmethod node->graphql :join
[node]
(let [{:keys [dispatch-key children params query]} node
graphql (map node->graphql children)
graphql-params (some-> params params->graphql)]
{:query [(name dispatch-key)
(:query graphql-params)
::separator
::field-brace-left
(->> (map :query graphql)
(interpose ::separator))
::field-brace-right]
:variables (apply set/union (:variables graphql-params) (map :variables graphql))}))
(defmethod node->graphql :union-entry
[node]
(let [{:keys [children union-key]} node
graphql (map node->graphql children)]
{:query [::union-signifier ::separator (name union-key) ::separator
::field-brace-left
(->> (map :query graphql)
(interpose ::separator))
::field-brace-right]
:variables (apply set/union (map :variables graphql))}))
(defmethod node->graphql :union
[node]
(let [{:keys [children]} node
graphql (map node->graphql children)]
{:query (->> (map :query graphql)
(interpose ::separator))
:variables (apply set/union (map :variables graphql))}))
(defmethod node->graphql :root
[node]
(let [{:keys [children]} node
graphql (map node->graphql children)]
{:query [::field-brace-left
(->> (map :query graphql)
(interpose ::separator))
::field-brace-right]
:variables (apply set/union (map :variables graphql))}))
(defn wrap-top-level-query [{:keys [query variables]}]
[::query-signifier
::separator
(when (seq variables)
[::arg-brace-left (->> (for [{:keys [unique-name type]} variables]
[::arg-signifier unique-name ::arg-separator type])
(interpose ::arg-list-separator))
::arg-brace-right])
query])
(defn query->graphql [query]
(let [ast (om/query->ast query)
{:keys [variables] :as graphql} (node->graphql ast)]
{:query (str/join (map #(get graphql-symbols % %) (flatten (wrap-top-level-query graphql))))
:variables (->> (for [{:keys [unique-name value] :as v} variables]
[unique-name value])
(into {}))}))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment