Repository: mirumee/ariadne-codegen (python)

Issue:
Incorrect default value for queries with `@include` directive
First of all, I loved the project. It has everything that anyone can expect.

Recently I ran into an issue, When the field name is in camelCase and uses `@include` directive the generated pydantic code doesn't generate proper default value (`None`)

I have used https://graphqlzero.almansi.me/api schema for testing purpose

`queries.graphql`:
```gql
query foo{
  postData: post (id: 1) @include(if: true)  {
    id
  }
}
```

generated pydantic code:
```py
from typing import Optional

from pydantic import Field

from .base_model import BaseModel


class Foo(BaseModel):
    post_data: Optional["FooPostData"] = Field(alias="postData")


class FooPostData(BaseModel):
    id: Optional[str]
```

`post_data` should be `Field(None, alias="postData")` because it's optional.

Pull request description:
Fix: Include directive result type when using `convert_to_snake_case` option
Fixes #272 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f61db31..f4d7f2c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,7 @@
 - Added `ClientForwardRefsPlugin` to standard plugins.
 - Re-added `model_rebuild` calls for input types with forward references.
 - Fixed fragments on interfaces being omitted from generated client.
+- Fixed `@Include` directive result type when using `convert_to_snake_case` option.
 
 
 ## 0.13.0 (2024-03-4)
diff --git a/ariadne_codegen/client_generators/constants.py b/ariadne_codegen/client_generators/constants.py
index 5cecf20..fe614d2 100644
--- a/ariadne_codegen/client_generators/constants.py
+++ b/ariadne_codegen/client_generators/constants.py
@@ -52,6 +52,7 @@ TYPING_MODULE = "typing"
 PYDANTIC_MODULE = "pydantic"
 FIELD_CLASS = "Field"
 ALIAS_KEYWORD = "alias"
+DEFAULT_KEYWORD = "default"
 DISCRIMINATOR_KEYWORD = "discriminator"
 MODEL_VALIDATE_METHOD = "model_validate"
 PLAIN_SERIALIZER = "PlainSerializer"
diff --git a/ariadne_codegen/client_generators/result_types.py b/ariadne_codegen/client_generators/result_types.py
index 24326d1..e94674b 100644
--- a/ariadne_codegen/client_generators/result_types.py
+++ b/ariadne_codegen/client_generators/result_types.py
@@ -51,6 +51,7 @@ from .constants import (
     ANY,
     BASE_MODEL_CLASS_NAME,
     BEFORE_VALIDATOR,
+    DEFAULT_KEYWORD,
     DISCRIMINATOR_KEYWORD,
     FIELD_CLASS,
     LIST,
@@ -437,6 +438,11 @@ class ResultTypesGenerator:
         if is_union(field_implementation.annotation):
             keywords[DISCRIMINATOR_KEYWORD] = generate_constant(TYPENAME_ALIAS)
 
+        if keywords and isinstance(field_implementation.value, ast.Constant):
+            keywords[DEFAULT_KEYWORD] = generate_constant(
+                field_implementation.value.value
+            )
+
         if keywords:
             field_implementation.value = generate_pydantic_field(keywords)
 


Test patch:
diff --git a/tests/client_generators/result_types_generator/schema.py b/tests/client_generators/result_types_generator/schema.py
index 2ad4efb..6ae1cff 100644
--- a/tests/client_generators/result_types_generator/schema.py
+++ b/tests/client_generators/result_types_generator/schema.py
@@ -50,6 +50,7 @@ type CustomType3 {
   field1: CustomType1!
   field2: CustomType1!
   field3: CustomType1
+  camelCaseField: CustomType1
 }
 
 enum CustomEnum {
diff --git a/tests/client_generators/result_types_generator/test_directives.py b/tests/client_generators/result_types_generator/test_directives.py
index 96e9a7e..7c38962 100644
--- a/tests/client_generators/result_types_generator/test_directives.py
+++ b/tests/client_generators/result_types_generator/test_directives.py
@@ -6,6 +6,7 @@ from graphql import OperationDefinitionNode, build_ast_schema, parse
 
 from ariadne_codegen.client_generators.constants import (
     BASE_MODEL_CLASS_NAME,
+    FIELD_CLASS,
     INCLUDE_DIRECTIVE_NAME,
     MIXIN_FROM_NAME,
     MIXIN_IMPORT_NAME,
@@ -215,3 +216,49 @@ def test_generator_returns_module_with_handled_skip_and_include_directives(direc
     assert class_def.name == "CustomQueryQuery3"
     assert compare_ast(class_def.body[0], expected_field_def_1)
     assert compare_ast(class_def.body[2], expected_field_def_2)
+
+
+@pytest.mark.parametrize("directive", [INCLUDE_DIRECTIVE_NAME, SKIP_DIRECTIVE_NAME])
+def test_generator_returns_module_with_handled_skip_and_include_directives_snake_case(
+    directive,
+):
+    query_str = f"""
+    query CustomQuery {{
+        query3 {{
+            camelCaseField @{directive} {{
+                fielda
+            }}
+        }}
+    }}
+    """
+    expected_field_def_3 = ast.AnnAssign(
+        target=ast.Name(id="camel_case_field"),
+        annotation=ast.Subscript(
+            value=ast.Name(id=OPTIONAL),
+            slice=ast.Name(id='"CustomQueryQuery3CamelCaseField"'),
+        ),
+        value=ast.Call(
+            func=ast.Name(id=FIELD_CLASS),
+            args=[],
+            keywords=[
+                ast.keyword(arg="alias", value=ast.Constant(value="camelCaseField")),
+                ast.keyword(arg="default", value=ast.Constant(value=None)),
+            ],
+        ),
+        simple=1,
+    )
+
+    generator = ResultTypesGenerator(
+        schema=build_ast_schema(parse(SCHEMA_STR)),
+        operation_definition=cast(
+            OperationDefinitionNode, parse(query_str).definitions[0]
+        ),
+        enums_module_name="enums",
+        convert_to_snake_case=True,
+    )
+
+    module = generator.generate()
+
+    class_def = get_class_def(module, 1)
+    assert class_def.name == "CustomQueryQuery3"
+    assert compare_ast(class_def.body[0], expected_field_def_3)