mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-16 01:44:03 +03:00
23f32c3db4
closes https://github.com/hasura/graphql-engine/issues/8398 PR-URL: https://github.com/hasura/graphql-engine-mono/pull/4313 GitOrigin-RevId: 3f24434b8256ec30838ce0014a04f8dfdca7f0d5
94 lines
3.8 KiB
Go
94 lines
3.8 KiB
Go
package metadatautil
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
|
|
"cuelang.org/go/cue/cuecontext"
|
|
"cuelang.org/go/cue/format"
|
|
"cuelang.org/go/encoding/json"
|
|
"cuelang.org/go/encoding/yaml"
|
|
v3yaml "gopkg.in/yaml.v3"
|
|
)
|
|
|
|
// TODO: reuse https://github.com/hasura/graphql-engine-mono/blob/1c76a0bc4cd0004cc30c17ece672363c142296da/cli/internal/projectmetadata/handler.go#L294
|
|
// currently not possible because of the difference in type of struct elements.
|
|
// the above mentioned type uses interface{} as types for elements, which will not preserve
|
|
// order during unmarshalling. So here we have to tweak it to `yaml.Node`
|
|
type metadata struct {
|
|
Version v3yaml.Node `yaml:"version" mapstructure:"version"`
|
|
Sources v3yaml.Node `yaml:"sources,omitempty" mapstructure:"sources,omitempty"`
|
|
Tables v3yaml.Node `yaml:"tables,omitempty" mapstructure:"tables,omitempty"`
|
|
Functions v3yaml.Node `yaml:"functions,omitempty" mapstructure:"functions,omitempty"`
|
|
Actions v3yaml.Node `yaml:"actions,omitempty" mapstructure:"actions,omitempty"`
|
|
CustomTypes v3yaml.Node `yaml:"custom_types,omitempty" mapstructure:"custom_types,omitempty"`
|
|
RemoteSchemas v3yaml.Node `yaml:"remote_schemas,omitempty" mapstructure:"remote_schemas,omitempty"`
|
|
QueryCollections v3yaml.Node `yaml:"query_collections,omitempty" mapstructure:"query_collections,omitempty"`
|
|
AllowList v3yaml.Node `yaml:"allowlist,omitempty" mapstructure:"allowlist,omitempty"`
|
|
CronTriggers v3yaml.Node `yaml:"cron_triggers,omitempty" mapstructure:"cron_triggers,omitempty"`
|
|
Network v3yaml.Node `yaml:"network,omitempty" mapstructure:"network,omitempty"`
|
|
APILimits v3yaml.Node `yaml:"api_limits,omitempty" mapstructure:"api_limits,omitempty"`
|
|
RestEndpoints v3yaml.Node `yaml:"rest_endpoints,omitempty" mapstructure:"rest_endpoints,omitempty"`
|
|
InheritedRoles v3yaml.Node `yaml:"inherited_roles,omitempty" mapstructure:"inherited_roles,omitempty"`
|
|
|
|
// HGE Pro
|
|
GraphQLSchemaIntrospection v3yaml.Node `yaml:"graphql_schema_introspection,omitempty" mapstructure:"graphql_schema_introspection,omitempty"`
|
|
|
|
// note: update projectmetadata/handler.go.Metadata to reflect changes made here
|
|
// TODO: remove this note once the TODO item above (code reuse) is addressed
|
|
// untill it is addressed this struct & https://github.com/hasura/graphql-engine-mono/blob/1c76a0bc4cd0004cc30c17ece672363c142296da/cli/internal/projectmetadata/handler.go#L294
|
|
// has to be kept in sync manually.
|
|
}
|
|
|
|
func JSONToYAML(bs []byte) ([]byte, error) {
|
|
out := new(bytes.Buffer)
|
|
cueJSONDecoder := json.NewDecoder(nil, "", bytes.NewReader(bs))
|
|
for {
|
|
// ref: https://github.com/cue-lang/cue/blob/6bc922c848660781778819a90a343285d0906e2e/encoding/json/json_test.go#L120
|
|
cueExpr, err := cueJSONDecoder.Extract()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cue: reading metadata %w", err)
|
|
}
|
|
|
|
cueNode, err := format.Node(cueExpr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cue: formatting error %w", err)
|
|
}
|
|
_, err = fmt.Fprint(out, string(cueNode))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cue: failed writing parsed json to writer %w", err)
|
|
}
|
|
|
|
}
|
|
|
|
cueCtx := cuecontext.New()
|
|
cueVal := cueCtx.CompileBytes(out.Bytes())
|
|
|
|
// ref: https://github.com/cue-lang/cue/blob/6bc922c848660781778819a90a343285d0906e2e/encoding/yaml/yaml_test.go#L234
|
|
metadataYAML, err := yaml.Encode(cueVal)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// we have to preserve order of elements, so we have to use a datastructure which has that property
|
|
var md metadata
|
|
err = v3yaml.Unmarshal(metadataYAML, &md)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
buf := new(bytes.Buffer)
|
|
|
|
// TODO: use metadatobject.GetEncoder (currently not possible because of cyclic dependency)
|
|
enc := v3yaml.NewEncoder(buf)
|
|
enc.SetIndent(2)
|
|
err = enc.Encode(md)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return buf.Bytes(), nil
|
|
}
|