Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Demonstrate poor handling of cyclic datastructures #111

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

lelandbatey
Copy link
Contributor

What this PR does / why we need it

This PR is not meant to ever be merged. This is a demonstration of some broken behavior around handling datastructures with cyclic dependencies. The problem is if we provide a struct to MarshalQueryWithOptions() and that struct has cyclic fields, even if not populated, and even if we provide a Field that limits the output to a set depth, MarshalQueryWithOptions() will still recurse infinitely and cause a panic due to exhausting the stack.

This is a big problem because goql is a GraphQL library, and GraphQL is for querying graph datastructures, and datastructures in graphs will very commonly have cyclic relationships because graphs have cycles :)

The correct behavior would be to:

  1. If no Fields are provided, do not recursively walk into fields of structs that've already been walked. This is safe to do because GraphQL already doesn't allow infinite expansion; if you want relationships, even recursive ones, to a particular depth then GQL will force you to specify that in your query. Thus we can assume that you'll have to specify that to goql via a Fields param.
  2. If Fields are provided, we can recursively walk already walked fields, but only to the depth specified in those Fields.

Future work will have to be done to get this behavior to work.

Jira ID

No jira for this (yet)

Notes for your reviewers

@lelandbatey lelandbatey requested a review from a team as a code owner January 24, 2025 00:13
This PR is not meant to ever be merged. This is a demonstration of some
broken behavior around handling datastructures with cyclic dependencies.
The problem is if we provide a struct to `MarshalQueryWithOptions()` and
that struct has cyclic fields, even if not populated, and even if we
provide a Field that limits the output to a set depth,
`MarshalQueryWithOptions()` will still recurse infinitely and cause a
panic due to exhausting the stack.

This is a big problem because goql is a GraphQL library, and GraphQL is
for querying graph datastructures, and datastructures in graphs will
very commonly have cyclic relationships because graphs have cycles :)

The correct behavior would be to:

1. If no Fields are provided, do not recursively walk into fields of
   structs that've already been walked. This is safe to do because
   GraphQL already doesn't allow infinite expansion; if you want
   relationships, even recursive ones, to a particular depth then GQL
   will force you to specify that in your query. Thus we can assume that
   you'll have to specify that to `goql` via a `Fields` param.
2. If `Fields` *are* provided, we can recursively walk already walked
   fields, but only to the depth specified in those `Fields`.

Future work will have to be done to get this behavior to work.
@lelandbatey lelandbatey force-pushed the demo-broken-cycle-handling branch from bab60b7 to d3c70b3 Compare January 24, 2025 00:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant