private void AppendTypeCase(
            StringBuilder body,
            ResultParserMethodDescriptor methodDescriptor,
            Action <string, ResultTypeDescriptor> appendNewObject,
            string indent,
            string initialIndent)
        {
            if (methodDescriptor.PossibleTypes.Count == 1)
            {
                appendNewObject(initialIndent, methodDescriptor.PossibleTypes[0]);
            }
            else
            {
                body.AppendLine($"{initialIndent}switch(obj.GetProperty(\"__typeName\").GetString())");
                body.AppendLine($"{initialIndent}{{");

                foreach (ResultTypeDescriptor type in methodDescriptor.PossibleTypes)
                {
                    body.AppendLine($"{initialIndent}{indent}case \"{type.GraphQLTypeName}\":");
                    appendNewObject($"{initialIndent}{indent}{indent}", type);
                    body.AppendLine();
                }

                body.AppendLine($"{initialIndent}{indent}default:");
                body.Append($"{initialIndent}{indent}{indent}");
                body.Append($"throw new {Types.InvalidOperationException}();");

                body.Append($"{initialIndent}}}");
            }
        }
        private void AppendSetElement(
            StringBuilder body,
            string array,
            string counter,
            ResultParserMethodDescriptor methodDescriptor,
            string element,
            string indent,
            string initialIndent)
        {
            bool multipleTypes = methodDescriptor.PossibleTypes.Count > 0;

            AppendTypeCase(
                body,
                methodDescriptor,
                (ii, type) =>
            {
                body.Append($"{ii}{array}[{counter}] = ");
                AppendNewObject(
                    body,
                    BuildTypeName(type.Components, type.Components.Count - 1),
                    element,
                    type.Fields,
                    indent,
                    initialIndent);
                body.AppendLine(";");
                if (multipleTypes)
                {
                    body.Append($"{ii}break;");
                }
            },
                indent,
                initialIndent);
        }
        private void AppendNestedList(
            StringBuilder body,
            ResultParserMethodDescriptor methodDescriptor,
            string indent)
        {
            AppendNullHandling(
                body,
                "parent",
                "obj",
                IsNullable(methodDescriptor.ResultType.Components[0]),
                indent,
                string.Empty);

            body.AppendLine();
            body.AppendLine();

            AppendList(
                body,
                new ListInfo(
                    "obj",
                    "i",
                    "count",
                    "element",
                    "result",
                    BuildTypeName(methodDescriptor.ResultType.Components)),
                IsNullable(methodDescriptor.ResultType.Components[1]),
                listIndent => AppendList(
                    body,
                    new ListInfo(
                        "element",
                        "j",
                        "innerCount",
                        "innerElement",
                        "innerResult",
                        BuildTypeName(methodDescriptor.ResultType.Components, 1)),
                    IsNullable(methodDescriptor.ResultType.Components[2]),
                    elementIndent => AppendSetElement(
                        body,
                        "innerResult",
                        "j",
                        methodDescriptor,
                        "innerElement",
                        indent,
                        elementIndent),
                    indent, listIndent),
                indent, string.Empty);

            body.AppendLine();
            body.AppendLine();
            body.AppendLine("return result;");
        }
        private static CodeBlockBuilder CreateParseDataMethodBody(
            ResultParserMethodDescriptor methodDescriptor,
            string indent)
        {
            var body = new StringBuilder();

            body.Append($"return ");

            AppendNewObject(
                body,
                methodDescriptor.PossibleTypes[0].Name,
                "data",
                methodDescriptor.PossibleTypes[0].Fields,
                indent,
                string.Empty);

            body.Append(";");

            return(CodeBlockBuilder.FromStringBuilder(body));
        }
 private void AddParseMethod(
     ClassBuilder classBuilder,
     ResultParserMethodDescriptor methodDescriptor,
     string indent)
 {
     classBuilder.AddMethod(
         MethodBuilder.New()
         .SetAccessModifier(AccessModifier.Private)
         .SetInheritance(Inheritance.Override)
         .SetReturnType(
             $"{methodDescriptor.ResultType}?",
             IsNullable(methodDescriptor.ResultType.Components))
         .SetReturnType(
             $"{methodDescriptor.ResultType}",
             !IsNullable(methodDescriptor.ResultType.Components))
         .SetName(methodDescriptor.Name)
         .AddParameter(ParameterBuilder.New()
                       .SetType(Types.JsonElement)
                       .SetName("parent"))
         .AddCode(CreateParseMethodBody(methodDescriptor, indent)));
 }
        private CodeBlockBuilder CreateParseMethodBody(
            ResultParserMethodDescriptor methodDescriptor,
            string indent)
        {
            var body = new StringBuilder();

            if (methodDescriptor.ResultType.Components[0].IsList &&
                methodDescriptor.ResultType.Components[1].IsList)
            {
                AppendNestedList(body, methodDescriptor, indent);
            }
            else if (methodDescriptor.ResultType.Components[0].IsList)
            {
                AppendList(body, methodDescriptor, indent);
            }
            else
            {
                AppendObject(body, methodDescriptor, indent);
            }

            return(CodeBlockBuilder.FromStringBuilder(body));
        }
        private void AppendObject(
            StringBuilder body,
            ResultParserMethodDescriptor methodDescriptor,
            string indent)
        {
            AppendNullHandling(
                body,
                "parent",
                "obj",
                IsNullable(methodDescriptor.ResultType.Components[0]),
                indent,
                string.Empty);

            body.AppendLine();
            body.AppendLine();

            AppendTypeCase(
                body,
                methodDescriptor,
                (ii, type) =>
            {
                body.Append($"{ii}return ");

                AppendNewObject(
                    body,
                    type.Name,
                    "obj",
                    type.Fields,
                    indent,
                    ii);

                body.Append(";");
            },
                indent,
                string.Empty);
        }