metosin / oksa

Generate GraphQL queries using Clojure data structures.
Eclipse Public License 2.0
51 stars 1 forks source link

Support name transformers #8

Closed ilmoraunio closed 5 months ago

ilmoraunio commented 6 months ago

We should consider supporting non-standard compliant representations for field names through name transformers. The name transformers should convert the field names either at parse time or during unparse time.

Use cases / rationale

  1. Sometimes you need to use & preserve namespaces on keywords, see example from graphql-query library.

Paraphrasing the example behind the link:

(oksa.core/gql 
  [[:employee {:name-fn (fn [field-name]
                          (str (when (namespace field-name)
                                 (str (namespace field-name) "_"))
                               (name field-name)))}
    [:user/name :user/address]]])

; => ; => "{employee{user_name user_address}}"
  1. Some developers might prefer using kebab-casing on their field names even though the unparse could result in a camelCased output (or some other casing format), similar to how honeysql may sometimes transform hyphens to underscores for a more idiomatic Clojure~y representation.

Example:

(require '[camel-snake-kebab.core :as csk])

(oksa.core/gql 
  [[:employee {:name-fn csk/->camelCase}
    [:user-name :user-address]]])

; => ; => "{employee{userName userAddress}}"
ilmoraunio commented 5 months ago

During development, the API evolved a bit to support global transformer fns and local overrides. I also ended up introducing transformers not just for names, but also for fields, enums, directives, and types.

Tiny example:

(require '[camel-snake-kebab.core :as csk])

(oksa.core/gql*
  {:oksa/name-fn csk/->camelCase}
  [[:foo-bar {:alias :bar-foo
              :directives [:foo-bar]
              :arguments {:foo-arg :bar-value}}
    [:foo-bar]]
   :naked-foo-bar
   [:...
    [:foo-bar]]
   [:... {:on :foo-bar-fragment
          :directives [:foo-bar]}
    [:foo-bar]]])

; => "{barFoo:fooBar(fooArg:barValue)@fooBar{fooBar} nakedFooBar ...{fooBar} ...on fooBarFragment@fooBar{fooBar}}"

See more examples in the README or tests.