quiz icon indicating copy to clipboard operation
quiz copied to clipboard

how to cast a quiz.Query to JSON?

Open g-k opened this issue 5 years ago • 4 comments

Thanks for writing quiz it's been really helpful!

Not sure if there's a better to do this, but I've been paging over github repo adjacent data and extending edges to bulid out a quiz.Query object: https://github.com/mozilla-services/find-package-rugaru/blob/d89ddf661a8c36f6a68e6ae87f624df486571718/bin/fetch_github_metadata_for_repo.py

I'd like to serialize the Query to JSON. Is there a way to do that?

Something like the inverse of load. I've been staring at the quiz.utils.JSON, which seems like the right type to use, but I thought I'd ask the expert. Thanks!

g-k avatar Mar 16 '19 02:03 g-k

hi @g-k, what do you mean exactly by serializing a Query to JSON? Perhaps a simple example can help.

If a query looks like this:

query = schema.query[
    _
    .repository(owner='octocat', name='hello-world')[
        _
        .createdAt
        .description
    ]
]

as graphql:

>>> str(query)
query {
  repository(owner: "octocat", name: "Hello-World") {
    createdAt
    description
  }
}

What would you like the JSON serialized result to look like?

Like this?

>>> import json
>>> json.dumps(str(query))
'"query {\\n  repository(owner: \\"octocat\\", name: \\"Hello-World\\") {\\n    createdAt\\n    description\\n  }\\n}"'

ariebovenberg avatar Mar 16 '19 10:03 ariebovenberg

@ariebovenberg I'm interested in the response data. e.g. for the GQL query above:

>>> str(query)
query {
  repository(owner: "octocat", name: "hello-world") {
    createdAt
    description
  }
}

I can get the response as a Query object and as a JSON string:

>>> exec(query)
Query(repository=Repository(createdAt='2011-01-26T19:01:12Z', description='My first repository on GitHub!'))
>>> exec(str(query))
{'repository': {'createdAt': '2011-01-26T19:01:12Z', 'description': 'My first repository on GitHub!'}}

Is there a way to take a python response object and schema and serialize it to JSON? (the inverse of loading a JSON file + schema and populating python object would be good too but I think load does that). Basically, deferring the JSON serialization of the Python response object.

g-k avatar Mar 18 '19 15:03 g-k

To expand: my use case is populating a response Python object with additional data from multiple responses from pagination e.g.

>>> str(query)
query {
  repository(owner: "octocat", name: "linguist") {
    createdAt
    description
    languages(first: 1) {
      pageInfo {
        hasNextPage
        endCursor
      }
      totalCount
      totalSize
      edges {
        node {
          id
          name
        }
      }
    }
  }
}
>>> repo = exec(query)
>>> repo
Query(repository=Repository(createdAt='2016-08-02T17:35:14Z', description="Language Savant. If your repository's language is being reported incorrectly, send us a pull request!", languages=LanguageConnection(pageInfo=PageInfo(hasNextPage=True, endCursor='Y3Vyc29yOnYyOpHONHyIeA=='), totalCount=2, totalSize=205775, edges=[LanguageEdge(node=Language(id='MDg6TGFuZ3VhZ2UxNDE=', name='Ruby'))])))
>>> exec(str(query))
{'repository': {'createdAt': '2016-08-02T17:35:14Z', 'description': "Language Savant. If your repository's language is being reported incorrectly, send us a pull request!", 'languages': {'pageInfo':{'hasNextPage': True, 'endCursor': 'Y3Vyc29yOnYyOpHONHyIeA=='}, 'totalCount': 2, 'totalSize': 205775, 'edges': [{'node': {'id': 'MDg6TGFuZ3VhZ2UxNDE=', 'name': 'Ruby'}}]}}}
>>> assert repo.repository.languages.pageInfo.hasNextPage
>>> next_lang_query =  schema.query[
...     _
...     .repository(owner='octocat', name='linguist')[
...         _
...         .createdAt
...         .description
...         .languages(
...             first=1, after=repo.repository.languages.pageInfo.endCursor
...         )[
...             _.pageInfo[_.hasNextPage.endCursor].totalCount.totalSize.edges[
...                 _.node[_.id.name]
...             ]
...         ]
...     ]
... ]
>>> str(next_lang_query)
query {
  repository(owner: "octocat", name: "linguist") {
    createdAt
    description
    languages(first: 1, after: "Y3Vyc29yOnYyOpHONHyIeA==") {
      pageInfo {
        hasNextPage
        endCursor
      }
      totalCount
      totalSize
      edges {
        node {
          id
          name
        }
      }
    }
  }
}
>>> next_lang_repo = exec(next_lang_query)
>>> next_lang_repo
Query(repository=Repository(createdAt='2016-08-02T17:35:14Z', description="Language Savant. If your repository's language is being reported incorrectly, send us a pull request!", languages=LanguageConnection(pageInfo=PageInfo(hasNextPage=False, endCursor='Y3Vyc29yOnYyOpHONHyIeQ=='), totalCount=2, totalSize=205775, edges=[LanguageEdge(node=Language(id='MDg6TGFuZ3VhZ2UxMzk=', name='Shell'))])))
>>> exec(str(next_lang_query))
{'repository': {'createdAt': '2016-08-02T17:35:14Z', 'description': "Language Savant. If your repository's language is being reported incorrectly, send us a pull request!", 'languages': {'pageInfo': {'hasNextPage': False, 'endCursor': 'Y3Vyc29yOnYyOpHONHyIeQ=='}, 'totalCount': 2, 'totalSize': 205775, 'edges': [{'node': {'id': 'MDg6TGFuZ3VhZ2UxMzk=', 'name': 'Shell'}}]}}}
>>> # combine pages of query responses                                                                                                                                                                 
>>> repo.repository.languages.edges.extend(next_lang_repo.repository.languages.edges)
>>> repo
Query(repository=Repository(createdAt='2016-08-02T17:35:14Z', description="Language Savant. If your repository's language is being reported incorrectly, send us a pull request!", languages=LanguageConnection(pageInfo=PageInfo(hasNextPage=True, endCursor='Y3Vyc29yOnYyOpHONHyIeA=='), totalCount=2, totalSize=205775, edges=[LanguageEdge(node=Language(id='MDg6TGFuZ3VhZ2UxNDE=', name='Ruby')), LanguageEdge(node=Language(id='MDg6TGFuZ3VhZ2UxMzk=', name='Shell'))])))
>>> str(repo)
Query(repository=Repository(createdAt='2016-08-02T17:35:14Z', description="Language Savant. If your repository's language is being reported incorrectly, send us a pull request!", languages=LanguageConnection(pageInfo=PageInfo(hasNextPage=True, endCursor='Y3Vyc29yOnYyOpHONHyIeA=='), totalCount=2, totalSize=205775, edges=[LanguageEdge(node=Language(id='MDg6TGFuZ3VhZ2UxNDE=', name='Ruby')), LanguageEdge(node=Language(id='MDg6TGFuZ3VhZ2UxMzk=', name='Shell'))])))
>>> 

Is there something like?

>>> quiz.dump(combined_repo, schema, type=quiz.utils.JSON)  # or json.dumps
{'repository': {'createdAt': '2016-08-02T17:35:14Z', 'description': "Language Savant. If your repository's language is being reported incorrectly, send us a pull request!", 'languages': {'pageInfo': {'hasNextPage': False, 'endCursor': 'Y3Vyc29yOnYyOpHONHyIeQ=='}, 'totalCount': 2, 'totalSize': 205775, 'edges': [{'node': {'id': 'MDg6TGFuZ3VhZ2UxNDE=', 'name': 'Ruby'}}, {'node': {'id': 'MDg6TGFuZ3VhZ2UxMzk=', 'name': 'Shell'}}]}}}

#22 might be related.

g-k avatar Mar 18 '19 16:03 g-k

Hmm, I guess it makes sense for the raw JSON to be accessible in a query. I'll see if I can fit it into a coming release.

As a current workaround, you can use the request metadata (introduced in 0.1.5):

result = quiz.execute(next_lang_query)
as_json = json.loads(result.__metadata__.response.content.decode())

I don't know about retrieving an object, mutating it, and dumping it back to JSON though...

ariebovenberg avatar Mar 20 '19 20:03 ariebovenberg