Closed indraneelmax closed 1 year ago
Hi indraneelmax,
Thanks for pointing out your issue.
I have been looking into the tests and actually there are many cases where the code generator have created a class representing a query with args and a list of objects as payload.
In your case it should have created a type list_user[User]
where list_user
is a class inheriting list.
To expose you some concrete examples taken from version 1.1.0 (present on pip):
Given a query type like this into the RapidApi schema:
{
"name": "extensions",
"description": "Get extensions for an API",
"args": [
{
"name": "client",
"description": null,
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "page",
"description": null,
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "path",
"description": null,
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
}
],
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "Extension",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
A GQLQuery
class gets created:
class extensions(GQLQuery):
class ExtensionArgs(GQLArgsSet, GQLObject):
client: str
page: str
path: str
_args: ExtensionArgs
type: list_Extension[Extension]
ref: https://github.com/dapalex/py-graphql-mapper/blob/1.1.0/tests/output/rapidapi_nodesc/queries.py#L241
The Extension
class:
class Extension(GQLObject):
id: ID
name: str
description: str
title: str
url: str
sourceUrl: str
sourceType: str
slugifiedKey: str
isEnabled: bool
loggedInRequired: bool
path: str
extensionConsumers: ExtensionConsumer
createdAt: DateTime
updatedAt: DateTime
deletedAt: DateTime
topic: str
order: int
And the list_Extension
class inheriting list as Payload:
class list_Extension(list, Extension): pass
Unluckily, there is only one case in Github API similar to your situation:
Query codesOfConduct
: https://github.com/dapalex/py-graphql-mapper/blob/1.1.0/tests/output/github_nodesc/queries.py#L26
The list as payload: https://github.com/dapalex/py-graphql-mapper/blob/1.1.0/tests/output/github_nodesc/queries.py#L9
Class codeOfConduct
: https://github.com/dapalex/py-graphql-mapper/blob/1.1.0/tests/output/github_nodesc/gql_simple_types.py#L1102
There are other cases in the tests with the same mapping logic.
My first guess is that in your situation there could be some different way of defining the type that I didn't encounter neither managed, I'll try to dig into the process to see if I can find any flaw, in the meanwhile I would ask you more details if you can, among them:
Thanks again
Thank you for your quick response.
class list_GQLObject(list, GQLObject): pass
and similar class NonNull_list_GQLObject
in it.Also, I am using https://strawberry.rocks/docs/guides/tools#merge_types
Query = merge_types(
"Query",
(
user_graphql.Query,
test_graphql.Query,
),
)
Mutation = merge_types(
"Mutation",
(
user_graphql.Mutation,
test_graphql.Mutation,
),
)
Thank you for sharing those examples. I also wanted to point out -
@strawberry.type
class MyQuery:
list_users: List[User] = strawberry.field(resolver=resolve_list_users)
Hi indraneelmax,
Thanks for the prompt feedback.
For the last issue regarding the python classes not generated following the name I am not exactly sure of what you mean. Right now the queries get fetched from the fields within a type of kind OBJECT with name "Query".
.................
"types": [
{
"kind": "OBJECT",
"name": "Query",
"description": null,
"fields": [
{
.................
Do you mean parameterizing the name following the name in queryType?
.................
"__schema": {
"queryType": {
"name": "Query"
},
.................
For the main issue I have found actually a bug during the construction of the main schema python class, in the next few days I should be able to release a new version with the fix. So for the example you noticed the query licenses will have to be:
class licenses(GQLQuery):
"""
licenses - Return a list of known open source licenses
"""
type: NonNull_list_License[License]
This will probably solve your issue with listUsers
query as well.
Note: The example you showed about License [e58e1ad] refers to an older version (1.0.0 in January), the last version is 1.1.0 (February)
I pushed the fix in the feature branch associated with this issue, if you want to try it now you can use this https://github.com/dapalex/py-graphql-mapper/tree/21-no-support-for-list-return-types
Anyway I will publish a new version of the library with the fix soon
Thanks
For the last issue regarding the python classes not generated following the name I am not exactly sure of what you mean.
The below class MyQuery
does not generate schema for list_users
@strawberry.type
class MyQuery:
list_users: List[User] = strawberry.field(resolver=resolve_list_users)
while below class Query
generates schema for list_users
@strawberry.type
class Query:
list_users: List[User] = strawberry.field(resolver=resolve_list_users)
Thank you for the fix branch, I will try to give it a shot and get back to you.
Thanks, I just pushed also that change. Now queries don't get recognized by the canonical name "Query" but whatever name has been defined in
"queryType": {
"name": "......"
},
Hi, Your branch does fix the list return types ( I still have to pull and test for the name fix).
class listUsers(GQLQuery):
class UserArgs(GQLArgsSet, GQLObject):
name: NonNull_str
login: NonNull_str
aggregateId: NonNull_str
limit: NonNull_int
_args: UserArgs
type: NonNull_list_User[User]
class User(GQLObject):
aggregateId: str
login: str
name: str
class NonNull_list_User(list, User): pass
set_show
method through which I could set fields to false, but that seems to create a problem when converting the fetched result into python object via map_gqldata_to_obj
. For e.g
query = listUsers(limit=2) # from queries.py
query.set_show("listUsers.aggregateId", False) # Do not want the aggregateID field retured back as part of User.
For above query for listUsers is returning a json response like below -
{'data': {'listUsers': [ {'login': 'testUser2', 'name': 'Test User 2 '}, { 'login': 'testUser', 'name': 'Test User 1 '}]}}
gql_response = GQLResponse(response, log_progress=True)
gql_response.map_gqldata_to_obj(query.type)
print('resultObject: ' + str(gql_response.result_obj))
ERROR:root:Setting value for element aggregateId failed - can only concatenate str (not "NonNull_list_User") to str ERROR:root:Setting value for element aggregateId failed - can only concatenate str (not "NonNull_list_User") to str resultObject: NonNull_list_User(aggregateId='', login='testUser', name='Test User 1 ')
2. For the same query for `listUsers` as from above notice that the `gql_response.result_obj` has just one user unfortunately (event without using `set_show`) -
resultObject: NonNull_list_User(aggregateId='', login='testUser', name='Test User 1 ')
For a query schema like the above it generates Python objects like -
The
type
should beList[User]
instead of justUser
.Using the query python class
listUsers
to fetch users works fine but when we try to convert the result into python objects (viaGQLResponse.map_gqldata_to_obj
) it fails to give correct data throwing below errors asbuilder.QueryBuilder.set_py_fields
expectsdataInput
to be adict
instead of a list as in this case.Is this expected or am I doing something wrong?