Ejemplo n.º 1
0
func IsValidGoValue(value interface{}, typ typs.QLInputType) bool {
	v := reflect.ValueOf(value)
	if typ, ok := typ.(*typs.QLNonNull); ok {
		if value == nil || v.IsNil() {
			return false
		}
		nullableType := typ.OfType.(typs.QLInputType)
		return IsValidGoValue(value, nullableType)
	}

	if value == nil || v.IsNil() {
		return true
	}

	v = reflect.Indirect(v)
	switch typ := typ.(type) {
	case *typs.QLList:
		itemType := typ.OfType.(typs.QLInputType)
		if v.Kind() == reflect.Slice || v.Kind() == reflect.Array {
			for i, n := 0, v.Len(); i < n; i++ {
				item := v.Index(i)
				if !IsValidGoValue(item, itemType) {
					return false
				}
			}
		}
		return IsValidGoValue(value, itemType)

	case *typs.QLInputObject:
		if v.Kind() != reflect.Struct {
			return false
		}
		t := v.Type()
		fieldsMap := typ.GetFields()
		for i, n := 0, t.NumField(); i < n; i++ {
			field := t.Field(i)
			fieldValue := v.Field(i)
			fieldType := fieldsMap[field.Name]
			if fieldType == nil || !IsValidGoValue(fieldValue, fieldType.Type) {
				return false
			}
		}
		return true

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

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

	default:
		panic("unreachable")
	}
}
Ejemplo n.º 2
0
/**
 * Produces a Go value given a GraphQL Value AST.
 *
 * A GraphQL type must be provided, which will be used to interpret different
 * GraphQL Value literals.
 *
 * | GraphQL Value        | JSON Value    |
 * | -------------------- | ------------- |
 * | Input Object         | Object        |
 * | List                 | Array         |
 * | Boolean              | Boolean       |
 * | String / Enum Value  | String        |
 * | Int / Float          | Number        |
 *
 */
func ValueFromAST(
	valueAST lang.IValue,
	typ typs.QLInputType,
	variables map[string]interface{},
) interface{} {
	if typ, ok := typ.(*typs.QLNonNull); ok {
		nullableType := typ.OfType.(typs.QLInputType)
		return ValueFromAST(valueAST, nullableType, variables)
	}

	if IsNil(valueAST) {
		return nil
	}

	if valueAST, ok := valueAST.(*lang.Variable); ok {
		variableName := valueAST.Name.Value
		return variables[variableName]
	}

	switch typ := typ.(type) {
	case *typs.QLList:
		if valueAST, ok := valueAST.(*lang.ListValue); ok {
			itemType := typ.OfType.(typs.QLInputType)
			result := make([]interface{}, len(valueAST.Values))[:0]
			for _, itemAST := range valueAST.Values {
				result = append(result, ValueFromAST(itemAST, itemType, variables))
			}
			return result
		}
		return []interface{}{ValueFromAST(valueAST, typ, variables)}

	case *typs.QLInputObject:
		valueAST, ok := valueAST.(*lang.ObjectValue)
		if !ok {
			return nil
		}

		fieldASTMap := make(map[string]*lang.ObjectField)
		for _, fieldAST := range valueAST.Fields {
			fieldASTMap[fieldAST.Name.Value] = fieldAST
		}

		result := make(map[string]interface{})
		fields := typ.GetFields()
		for fieldName, field := range fields {
			fieldAST := fieldASTMap[fieldName]
			var fieldValue interface{}
			if fieldAST != nil {
				fieldValue = ValueFromAST(fieldAST.Value, field.Type, variables)
			}
			if IsNil(fieldValue) {
				fieldValue = field.DefaultValue
			}
			if !IsNil(fieldValue) {
				result[fieldName] = fieldValue
			}
		}
		return result

	case *typs.QLScalar:
		parsed := typ.ParseLiteral(valueAST)
		if IsNil(parsed) {
			return nil
		}
		return parsed

	default:
		throw("Must be input type")
		return nil
	}
}
Ejemplo n.º 3
0
func IsValidLiteralValue(typ typs.QLInputType, valueAST lang.IValue) bool {
	if typ, ok := typ.(*typs.QLNonNull); ok {
		if IsNil(valueAST) {
			return false
		}

		ofType := typ.OfType.(typs.QLInputType)
		return IsValidLiteralValue(ofType, valueAST)
	}

	if IsNil(valueAST) {
		return false
	}

	if _, ok := valueAST.(*lang.Variable); ok {
		return true
	}

	if typ, ok := typ.(*typs.QLList); ok {
		itemType := typ.OfType.(typs.QLInputType)
		if valueAST, ok := valueAST.(*lang.ListValue); ok {
			for i := range valueAST.Values {
				return IsValidLiteralValue(itemType, valueAST.Values[i])
			}
		}
	}

	if typ, ok := typ.(*typs.QLInputObject); ok {
		if _, ok := valueAST.(*lang.ObjectValue); !ok {
			return false
		}

		fields := typ.GetFields()
		fieldASTs := valueAST.(*lang.ObjectValue).Fields
		refinedFieldASTs := []interface{}{}

		for i := range fieldASTs {
			if fields[fieldASTs[i].Name.Value] == nil {
				return false
			}

			refinedFieldASTs = append(refinedFieldASTs, fieldASTs[i])
		}

		fieldASTMap := make(map[string]interface{})
		for _, fieldAST := range refinedFieldASTs {
			fieldASTMap[fieldAST.(lang.ObjectField).Name.Value] = fieldAST
		}

		for k, v := range fields {
			return IsValidLiteralValue(v.Type, fieldASTMap[k].(*lang.ObjectField).Value)
		}

	}

	if typ, ok := typ.(*typs.QLScalar); ok {
		return !IsNil(typ.ParseLiteral(valueAST))
	}

	if typ, ok := typ.(*typs.QLEnum); ok {
		return !IsNil(typ.ParseLiteral(valueAST))
	}

	return false
}