From 5e174520f8744ae2cc60d195b3c671c666303e33 Mon Sep 17 00:00:00 2001 From: tangkikodo Date: Thu, 2 Jul 2026 13:24:00 +0800 Subject: [PATCH] fix(sdl): expose limit/offset args on paginated list fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SDL generator rendered paginated list fields without args while the introspection path declared `limit` / `offset` — any client reading the schema via SDL (codegen tools, AI agents, GraphiQL alternatives) could not tell these fields were paginated, making the feature unreachable for them. GraphQL spec requires field args to be declared in SDL. Reuses `_is_paginated_relationship` to render paginated fields as `{field}(limit: Int, offset: Int = 0): {Type}Result!`. Offset default aligns with introspection's `defaultValue: "0"`. Closes #85. Co-Authored-By: Claude Opus 4.7 --- src/nexusx/sdl_generator.py | 10 +++++++++- tests/test_pagination_mixed.py | 19 ++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/nexusx/sdl_generator.py b/src/nexusx/sdl_generator.py index 48f6773..e60ea7b 100644 --- a/src/nexusx/sdl_generator.py +++ b/src/nexusx/sdl_generator.py @@ -358,7 +358,15 @@ def _generate_type(self, entity: type[SQLModel]) -> str: # Check if it's a relationship (references another entity) gql_type = self._type_hint_to_graphql(hint, entity, field_name) if gql_type: - fields.append(f" {field_name}: {gql_type}") + # Paginated list fields declare limit/offset args to match + # the introspection path — without them, SDL-only clients + # cannot tell the field is paginated. + if self._is_paginated_relationship(entity, field_name): + fields.append( + f" {field_name}(limit: Int, offset: Int = 0): {gql_type}" + ) + else: + fields.append(f" {field_name}: {gql_type}") # Build type definition with optional description type_def = f"type {entity.__name__} {{\n{chr(10).join(fields)}\n}}" diff --git a/tests/test_pagination_mixed.py b/tests/test_pagination_mixed.py index b72278c..3a63b01 100644 --- a/tests/test_pagination_mixed.py +++ b/tests/test_pagination_mixed.py @@ -87,7 +87,24 @@ def test_paginated_list_renders_as_result_type(self): assert "items: [SortedKid!]!" in sdl parent_block = sdl.split("type MixedParent {", 1)[1].split("}", 1)[0] - assert "sorted_kids: SortedKidResult!" in parent_block + # Field type is SortedKidResult! (non-null). Field may declare args + # — that's covered by test_paginated_field_exposes_limit_offset_args. + assert ": SortedKidResult!" in parent_block + + def test_paginated_field_exposes_limit_offset_args(self): + """Issue #85: paginated list field must declare limit/offset args in SDL. + + SDL and introspection must agree — without args in SDL, any client + that reads the schema via SDL (codegen tools, AI agents, GraphiQL + alternatives) cannot tell the field is paginated. + """ + registry = _make_registry() + sdl = SDLGenerator(MIXED_ENTITIES).generate( + enable_pagination=True, loader_registry=registry + ) + + parent_block = sdl.split("type MixedParent {", 1)[1].split("}", 1)[0] + assert "sorted_kids(limit: Int, offset: Int = 0): SortedKidResult!" in parent_block def test_non_paginated_list_renders_as_plain_list(self): """raw_kids (no order_by) → [RawKid!]! with no pagination args."""