Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: separate graphql compute logic out of source generator #24

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions codegen/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/dagger.gen.go linguist-generated
/internal/dagger/** linguist-generated
/internal/querybuilder/** linguist-generated
/internal/telemetry/** linguist-generated
4 changes: 4 additions & 0 deletions codegen/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/dagger.gen.go
/internal/dagger
/internal/querybuilder
/internal/telemetry
150 changes: 150 additions & 0 deletions codegen/codegen.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
syntax = "proto3";

package codegen;

option go_package = "./proto/codegen";

// Deprecation message.
message Deprecation { string reason = 1; }

message ObjectTypeRef {
// Type name.
string name = 1;
}

message ScalarTypeRef {
// Type name.
string name = 1;
}

message EnumTypeRef {
// Type name.
string name = 1;
}

message ListTypeRef {
// List of type.
TypeRef of_type = 1;
}

message TypeRef {
// This field is optional type?
bool nullable = 1;

// What is the type of this field.
oneof type {
ObjectTypeRef object_type = 5;
ScalarTypeRef scalar_type = 6;
EnumTypeRef enum_type = 7;
ListTypeRef list_type = 8;
}
}

// The value in Enum.
message EnumValue {
// Enum value name
string name = 1;

// Enum value description.
string description = 2;

// Tells this enum is deprecated.
optional Deprecation deprecated = 3;
}

message Field {
// Field name.
string name = 1;

// Field documentation.
string description = 2;

// The default value of this field. It can be null.
optional string default_value = 3;

// The type of this field.
TypeRef type = 4;

optional Deprecation deprecated = 5;
}

// Function definition.
message Function {
// Function name.
string name = 1;

// Funciton documentation.
string description = 2;

// Function required arguments.
repeated Field required_args = 3;

// Function optional arguments.
repeated Field optional_args = 4;

// Function return type.
TypeRef return_type = 5;

// Tells this function already deprecated.
optional Deprecation deprecated = 6;
}

// GraphQL object.
message Object {
// Scalar name.
string name = 1;

// Scalar documentation.
string description = 2;

// Avaiable functions for this object.
//
// This mapped from `fields` in GraphQL object world.
repeated Function functions = 3;
}

// GraphQL scalar.
message Scalar {
// Scalar name.
string name = 1;

// Scalar documentation.
string description = 2;
}

// GraphQL input object.
message Input {
// Input object name.
string name = 1;

// Input object documentaion.
string description = 2;

// Fields inside this input object.
repeated Field fields = 3;
}

// GraphQL enum.
message Enum {
// Enum name.
string name = 1;

// Enum documentation.
string description = 2;

// Available enum values.
repeated EnumValue values = 3;

optional Deprecation deprecated = 4;
}

message Type {
oneof value {
Object object = 1;
Scalar scalar = 2;
Input input = 3;
Enum enum = 4;
}
}

message Schema { repeated Type types = 1; }
193 changes: 193 additions & 0 deletions codegen/codegen/transform.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
// Package codegen takes care about how to transfrom GraphQL introspection into
// Protobuf format.
package codegen

import (
"google.golang.org/protobuf/proto"

"dagger/codegen/introspection"
codegenpb "dagger/codegen/proto/codegen"
)

// Transform introspection JSON into Protobuf format.
func Transform(schema *introspection.Schema) ([]byte, error) {
pb := doTransform(schema)
return proto.Marshal(pb)
}

func TransformJson(introspectionJson string) ([]byte, error) {
schema, err := introspection.FromJson(introspectionJson)
if err != nil {
return nil, err
}
return Transform(schema)
}

func doTransform(schema *introspection.Schema) *codegenpb.Schema {
schemapb := &codegenpb.Schema{}

for _, type_ := range schema.Types {
schemapb.Types = append(schemapb.Types, transformType(type_))
}

return schemapb
}

func transformType(type_ *introspection.Type) *codegenpb.Type {
switch type_.Kind {
case introspection.TypeKindScalar:
return transformScalarType(type_)
case introspection.TypeKindEnum:
return transformEnumType(type_)
case introspection.TypeKindInputObject:
return transformInputObjectType(type_)
case introspection.TypeKindObject:
return transformObjectType(type_)
}
panic("Type kind " + type_.Kind + " is not supported")
}

func transformScalarType(type_ *introspection.Type) *codegenpb.Type {
return &codegenpb.Type{
Value: &codegenpb.Type_Scalar{
Scalar: &codegenpb.Scalar{
Name: normalizeName(type_.Name),
Description: *type_.Description,
},
},
}
}

func transformEnumType(type_ *introspection.Type) *codegenpb.Type {
values := make([]*codegenpb.EnumValue, len(type_.EnumValues))

for i, ev := range type_.EnumValues {
var deprecation *codegenpb.Deprecation
if ev.IsDeprecated {
deprecation = &codegenpb.Deprecation{
Reason: ev.DeprecationReason,
}
}
values[i] = &codegenpb.EnumValue{
Name: ev.Name,
Description: ev.Description,
Deprecated: deprecation,
}
}

return &codegenpb.Type{
Value: &codegenpb.Type_Enum{
Enum: &codegenpb.Enum{
Name: normalizeName(type_.Name),
Description: *type_.Description,
Values: values,
},
},
}
}

func transformInputObjectType(type_ *introspection.Type) *codegenpb.Type {
fields := make([]*codegenpb.Field, len(type_.InputFields))

for i, iv := range type_.InputFields {
iv := iv

fields[i] = &codegenpb.Field{
Name: iv.Name,
Description: iv.Description,
DefaultValue: iv.DefaultValue,
Type: toTypeRef(iv.Type),
}
}

return &codegenpb.Type{
Value: &codegenpb.Type_Input{
Input: &codegenpb.Input{
Name: normalizeName(type_.Name),
Description: *type_.Description,
Fields: fields,
},
},
}
}

func transformObjectType(type_ *introspection.Type) *codegenpb.Type {
functions := make([]*codegenpb.Function, len(type_.Fields))

for i, f := range type_.Fields {
f := f

var deprecation *codegenpb.Deprecation
if f.IsDeprecated {
deprecation = &codegenpb.Deprecation{
Reason: f.DeprecationReason,
}
}

functions[i] = &codegenpb.Function{
Name: f.Name,
Description: f.Description,
ReturnType: toTypeRef(f.Type),
Deprecated: deprecation,
}
}

return &codegenpb.Type{
Value: &codegenpb.Type_Object{
Object: &codegenpb.Object{
Name: normalizeName(type_.Name),
Description: *type_.Description,
Functions: functions,
},
},
}
}

func toTypeRef(itr *introspection.TypeRef) (ctr *codegenpb.TypeRef) {
ctr = &codegenpb.TypeRef{
Nullable: itr.Kind != introspection.TypeKindNonNull,
}

if itr.Kind == introspection.TypeKindNonNull {
itr = itr.OfType
}

name := normalizeName(itr.Name)

switch itr.Kind {
case introspection.TypeKindEnum:
ctr.Type = &codegenpb.TypeRef_EnumType{
EnumType: &codegenpb.EnumTypeRef{Name: name},
}
return

case introspection.TypeKindObject:
ctr.Type = &codegenpb.TypeRef_ObjectType{
ObjectType: &codegenpb.ObjectTypeRef{Name: name},
}
return

case introspection.TypeKindScalar:
ctr.Type = &codegenpb.TypeRef_ScalarType{
ScalarType: &codegenpb.ScalarTypeRef{Name: name},
}
return

case introspection.TypeKindList:
ctr.Type = &codegenpb.TypeRef_ListType{
ListType: &codegenpb.ListTypeRef{
OfType: toTypeRef(itr.OfType),
},
}
return
}

panic("Type kind " + itr.Kind + " is not supported")
}

func normalizeName(name string) string {
if name == "Query" {
return "Client"
}
return name
}
Loading