Ejemplo n.º 1
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.º 2
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
}