Add an option to handle enums with ugly casing (#270)

There are a bunch of places in genqlient where we just kind of hope you
don't have ridiculous casing conflicts in your schema. Apparently with
enum values there are actual schemas that have this problem! Now we have
an option to disable. I ended up putting it all under `casing` instead
of in `bindings` so we can clearly document the list of algorithms we
support, and so we can have an `all_enums` value if you're working with
a schema with a lot of this; in the future we may want to add similar
behavior for types/fields, add more possible algorithms (e.g. to make
things unexported), etc.

I added tests for the new feature, although the way the tests are set up
it wasn't convenient to do so for a schema where this is actually
required. I also added a check for case conflicts that points you to
this option. (I don't want to do it automatically for reasons described
in the issue; mainly it just seemed a bit too magical.)

Fixes #265.
This commit is contained in:
Ben Kraft
2023-05-07 12:15:13 -07:00
committed by GitHub
parent 9b2f16c088
commit ff790e1c06
16 changed files with 375 additions and 17 deletions
+58
View File
@@ -31,6 +31,7 @@ type Config struct {
ClientGetter string `yaml:"client_getter"`
Bindings map[string]*TypeBinding `yaml:"bindings"`
PackageBindings []*PackageBinding `yaml:"package_bindings"`
Casing Casing `yaml:"casing"`
Optional string `yaml:"optional"`
OptionalGenericType string `yaml:"optional_generic_type"`
StructReferences bool `yaml:"use_struct_references"`
@@ -68,6 +69,59 @@ type PackageBinding struct {
Package string `yaml:"package"`
}
// CasingAlgorithm represents a way that genqlient can handle casing, and is
// documented further in the [genqlient.yaml docs].
//
// [genqlient.yaml docs]: https://github.com/Khan/genqlient/blob/main/docs/genqlient.yaml
type CasingAlgorithm string
const (
CasingDefault CasingAlgorithm = "default"
CasingRaw CasingAlgorithm = "raw"
)
func (algo CasingAlgorithm) validate() error {
switch algo {
case CasingDefault, CasingRaw:
return nil
default:
return errorf(nil, "unknown casing algorithm: %s", algo)
}
}
// Casing wraps the casing-related options, and is documented further in
// the [genqlient.yaml docs].
//
// [genqlient.yaml docs]: https://github.com/Khan/genqlient/blob/main/docs/genqlient.yaml
type Casing struct {
AllEnums CasingAlgorithm `yaml:"all_enums"`
Enums map[string]CasingAlgorithm `yaml:"enums"`
}
func (casing *Casing) validate() error {
if casing.AllEnums != "" {
if err := casing.AllEnums.validate(); err != nil {
return err
}
}
for _, algo := range casing.Enums {
if err := algo.validate(); err != nil {
return err
}
}
return nil
}
func (casing *Casing) forEnum(graphQLTypeName string) CasingAlgorithm {
if specificConfig, ok := casing.Enums[graphQLTypeName]; ok {
return specificConfig
}
if casing.AllEnums != "" {
return casing.AllEnums
}
return CasingDefault
}
// pathJoin is like filepath.Join but 1) it only takes two argsuments,
// and b) if the second argument is an absolute path the first argument
// is ignored (similar to how python's os.path.join() works).
@@ -172,6 +226,10 @@ func (c *Config) ValidateAndFillDefaults(baseDir string) error {
}
}
if err := c.Casing.validate(); err != nil {
return err
}
return nil
}