예제 #1
0
파일: values.go 프로젝트: ng-vu/graphql-go
/**
 * Given a type and any value, return a runtime value coerced to match the type.
 */
func coerceValue(typ typs.QLType, value interface{}) interface{} {
	if typ, ok := typ.(*typs.QLNonNull); ok {
		nullableType := typ.OfType
		return coerceValue(nullableType, value)
	}

	v := reflect.ValueOf(value)
	if value == nil || v.IsNil() {
		return nil
	}

	switch typ := typ.(type) {
	case *typs.QLList:
		itemType := typ.OfType
		if v.Kind() == reflect.Slice || v.Kind() == reflect.Array {
			result := make([]interface{}, v.Len())[:0]
			for i, n := 0, v.Len(); i < n; i++ {
				fieldValue := v.Field(i)
				result = append(result, coerceValue(itemType, fieldValue))
			}
			return result
		}
		return []interface{}{coerceValue(itemType, value)}

	case *typs.QLInputObject:
		fields := typ.GetFields()
		obj := make(map[string]interface{})
		for fieldName, field := range fields {
			runtimeField := v.FieldByName(fieldName)
			if !runtimeField.IsValid() {
				continue
			}

			fieldValue := coerceValue(field.Type, runtimeField.Interface())
			if fieldValue == nil {
				fieldValue = field.DefaultValue
			}
			if fieldValue != nil {
				obj[fieldName] = fieldValue
			}
		}
		return obj

	case *typs.QLScalar:
		return typ.ParseValue(value)

	case *typs.QLEnum:
		return typ.ParseValue(value)

	default:
		panic("Must be input type")
	}
}
예제 #2
0
파일: ast.go 프로젝트: ng-vu/graphql-go
func ASTFromValue(value interface{}, typ typs.QLType) lang.IValue {

	if typ, ok := typ.(*typs.QLNonNull); ok {
		return ASTFromValue(value, typ.OfType)
	}

	if IsNil(value) {
		return nil
	}

	val := reflect.ValueOf(value)
	val = reflect.Indirect(val)

	if val.Kind() == reflect.Array || val.Kind() == reflect.Slice {
		var itemType typs.QLType
		if typ, ok := typ.(*typs.QLList); ok {
			itemType = typ.OfType
		}

		values := []lang.IValue{}
		for i := 0; i < val.Len(); i++ {
			values = append(values, ASTFromValue(val.Index(i), itemType))
		}

		return &lang.ListValue{
			Values: values,
		}
	} else if typ, ok := typ.(*typs.QLList); ok {
		return ASTFromValue(value, typ.OfType)
	}

	if val.Kind() == reflect.Bool {
		return &lang.BooleanValue{
			Value: strconv.FormatBool(val.Bool()),
		}
	}

	if _, ok := typ.(*typs.QLScalar); ok {
		if val.Kind() == reflect.Int {
			return &lang.IntValue{
				Value: fmt.Sprintf("%v", val.Int()),
			}
		}

		if val.Kind() == reflect.Float64 {
			return &lang.FloatValue{
				Value: fmt.Sprintf("%v", val.Float()),
			}
		}
	}

	if val.Kind() == reflect.String {

		if _, ok := typ.(*typs.QLEnum); ok {
			matched, _ := regexp.MatchString(`^[_a-zA-Z][_a-zA-Z0-9]*$`, val.String())
			if matched {
				return &lang.EnumValue{
					Value: val.String(),
				}
			}
		}
		return &lang.StringValue{
			Value: val.String()[1 : val.Len()-1],
		}
	}

	v := val.Elem()

	fields := []*lang.ObjectField{}
	for i := 0; i < v.NumField(); i++ {
		valueField := v.Field(i)
		typeField := val.Type().Field(i)

		var fieldTyp typs.QLType

		if typ, ok := typ.(*typs.QLInputObject); ok {
			fieldDef := typ.GetFields()[typeField.Name]
			if fieldDef != nil {
				fieldTyp = fieldDef.Type
			}
		}

		fieldValue := ASTFromValue(valueField, fieldTyp)

		if fieldValue != nil {
			fields = append(fields, &lang.ObjectField{
				Name: &lang.Name{
					Value: typeField.Name,
				},
				Value: fieldValue,
			})
		}
	}

	return &lang.ObjectValue{
		Fields: fields,
	}

	return nil
}