func()

in codegen/method.go [1346:1552]


func (ms *MethodSpec) setParseQueryParamStatements(
	funcSpec *compile.FunctionSpec, packageHelper *PackageHelper, hasNoBody bool,
) error {
	// If a thrift field has a http.ref annotation then we
	// should not read this field from query parameters.
	var statements LineBuilder

	var finalError error
	var stack = []string{}
	seenIdents := map[string]int{}

	visitor := func(
		goPrefix string, thriftPrefix string, field *compile.FieldSpec,
	) bool {
		realType := compile.RootTypeSpec(field.Type)
		longFieldName := goPrefix + "." + PascalCase(field.Name)
		longQueryName, shortQueryParam := ms.getQueryParamInfo(field, thriftPrefix)

		// Skip if there are no query params in the field or its components
		if !ms.hasQueryParams(field, hasNoBody) {
			return false
		}

		if len(stack) > 0 {
			if !strings.HasPrefix(longFieldName, stack[len(stack)-1]) {
				stack = stack[:len(stack)-1]
				statements.append("}")
			}
		}

		customType, err := getCustomType(packageHelper, field.Type)
		if err != nil {
			finalError = err
			return true
		}

		var isList, isSet bool
		var customElemType string
		var isEnumElem bool
		switch t := realType.(type) {
		// Before you ask -- yes duplicated code because ValueSpec is not defined in the generic interface
		case *compile.ListSpec:
			isList = true
			customElemType, err = getCustomType(packageHelper, t.ValueSpec)
			if err != nil {
				finalError = err
				return true
			}
			_, isEnumElem = t.ValueSpec.(*compile.EnumSpec)
		case *compile.SetSpec:
			isSet = true
			customElemType, err = getCustomType(packageHelper, t.ValueSpec)
			if err != nil {
				finalError = err
				return true
			}
			_, isEnumElem = t.ValueSpec.(*compile.EnumSpec)
		case *compile.StructSpec:
			typeName, err := GoType(packageHelper, realType)
			if err != nil {
				finalError = err
				return true
			}

			if !field.Required {
				stack = append(stack, longFieldName)
				applicableQueryParams := ms.getContainedQueryParams(field, hasNoBody, "")

				statements.append("var _queryNeeded bool")
				statements.appendf("for _, _pfx := range %#v {", applicableQueryParams)
				statements.append("if _queryNeeded = req.HasQueryPrefix(_pfx); _queryNeeded {")
				statements.append("break")
				statements.append("}")
				statements.append("}")
				statements.append("if _queryNeeded {")
			}

			statements.appendf("if requestBody%s == nil {", longFieldName)
			statements.appendf("requestBody%s = &%s{}", longFieldName, typeName)
			statements.append("}")

			return false
		}
		isAggregate := isList || isSet // we do not support maps

		// For disambiguation of similar names
		baseIdent := makeUniqIdent(CamelCase(longQueryName), seenIdents)
		identifierName := baseIdent + "Query"
		okIdentifierName := baseIdent + "Ok"

		// make sure value is present
		if field.Required {
			statements.appendf("%s := req.CheckQueryValue(%q)", okIdentifierName, shortQueryParam)
			statements.appendf("if !%s {", okIdentifierName)
			statements.append("return ctx")
			statements.append("}")
		} else {
			statements.appendf("%s := req.HasQueryValue(%q)", okIdentifierName, shortQueryParam)
			statements.appendf("if %s {", okIdentifierName)
		}

		queryRValue := fmt.Sprintf("req.%s(%q)", getQueryMethodForType(realType), shortQueryParam)

		// Transform if enum
		if _, isEnumType := field.Type.(*compile.EnumSpec); isEnumType {
			statements.appendf("var %s %s", identifierName, customType)
			tmpVar := "_tmp" + identifierName
			statements.appendf("%s, ok := %s", tmpVar, queryRValue)
			statements.append("if ok {")
			statements.appendf("if err := %s.UnmarshalText([]byte(%s)); err != nil {",
				identifierName, tmpVar)
			statements.appendf("req.LogAndSendQueryError(err, %q, %q, %s)",
				"enum", shortQueryParam, tmpVar)
			statements.append("ok = false")
			statements.append("}")
			statements.append("}")
		} else {
			statements.appendf("%s, ok := %s", identifierName, queryRValue)
		}

		statements.append("if !ok {")
		statements.append("return ctx")
		statements.append("}")

		target := identifierName

		// If field is an "aggregate" with custom element types, we need to convert them first
		// Note that enums and typedefs are what get in here
		if customElemType != "" {
			target += "Final"
			valVar := "v"
			if isList {
				statements.appendf(
					"%s := make([]%s, len(%s))",
					target, customElemType, identifierName,
				)
				statements.appendf("for i, %s := range %s {", valVar, identifierName)
				if isEnumElem {
					tmpVar := "_tmp" + valVar
					statements.appendf("var %s %s", tmpVar, customElemType)
					statements.appendf("if err := %s.UnmarshalText([]byte(%s)); err != nil {",
						tmpVar, valVar)
					statements.appendf("req.LogAndSendQueryError(err, %q, %q, %s)",
						"enum", shortQueryParam, valVar)
					statements.append("return ctx")
					statements.append("}")
					valVar = tmpVar
				}
				statements.appendf("%s[i] = %s(%s)", target, customElemType, valVar)
				statements.append("}")
			} else if isSet {
				statements.appendf(
					"%s := make(map[%s]struct{}, len(%s))",
					target, customElemType, identifierName,
				)
				statements.appendf("for %s := range %s {", valVar, identifierName)
				if isEnumElem {
					tmpVar := "_tmp" + valVar
					statements.appendf("var %s %s", tmpVar, customElemType)
					statements.appendf("if err := %s.UnmarshalText([]byte(%s)); err != nil {",
						tmpVar, valVar)
					statements.appendf("req.LogAndSendQueryError(err, %q, %q, %s)",
						"enum", shortQueryParam, valVar)
					statements.append("return ctx")
					statements.append("}")
					valVar = tmpVar
				}
				statements.appendf("%s[%s(%s)] = struct{}{}", target, customElemType, valVar)
				statements.append("}")
			}
		}

		var deref string
		if !field.Required && !isAggregate {
			deref = "*"
			targetName := identifierName
			if customType != "" {
				targetName = fmt.Sprintf("%s(%s)", strings.ToLower(pointerMethodType(realType)), targetName)
			}
			target = fmt.Sprintf("ptr.%s(%s)", pointerMethodType(realType), targetName)
		}
		if customType != "" {
			target = fmt.Sprintf("(%s%s)(%s)", deref, customType, target)
		}
		statements.appendf("requestBody%s = %s", longFieldName, target)

		if !field.Required {
			statements.append("}")
		}

		// new line after block.
		statements.append("")
		return false
	}
	walkFieldGroups(compile.FieldGroup(funcSpec.ArgsSpec), visitor)

	for i := 0; i < len(stack); i++ {
		statements.append("}")
	}

	if finalError != nil {
		return finalError
	}

	ms.ParseQueryParamGoStatements = statements.GetLines()
	return nil
}