HoudiniGraphql / houdini

The disappearing GraphQL framework
http://www.houdinigraphql.com
MIT License
913 stars 98 forks source link

get the clean data types without the fragment types #1110

Closed macmillen closed 2 weeks ago

macmillen commented 1 year ago

Describe the feature

I want to create mocked data to test my svelte components with houdini fragments inside with a mocked service worker. For that I need the pure graphql types of the query without the $fragments keys.

I can achieve that with some really ugly type acrobatics:

type DashboardPayload = CleanseHoundini<
  Omit<Dashboard$result["dashboard"], "tiles"> & {
    tiles: (Omit<Dashboard$result["dashboard"]["tiles"][number], "widget"> & {
      widget: Widget$data;
    })[];
  },
  "Dashboard"
>;

export const baseDashboard: DashboardPayload = {
  __typename: "Dashboard",
  tiles: [{ widget: { id: "expected_visitor_count", ... } }],
};

the qgraphql query in +page.gql:

query Dashboard {
  dashboard {
    tiles {
      id
      position
      size
      widget {
        ...Widget
      }
    }
  }
}

the fragment inside the svelte component:

  $: widget = fragment(
    _widget,
    graphql(`
      fragment Widget on DashboardWidget {
        id
        timeSpan
        dataType
        data {
          ... on DashboardDataIntValue {
            prevValue
            value
          }
          ... on DashboardDataMoneyValue {
            prevMoneyValue: prevValue
            moneyValue: value
          }
          ... on Error {
            key
            messages
          }
        }
      }
    `)
  );

But that's really a bad dev experience.

Proposed solution

Criticality

cool improvement, my projects will benefit from it

AlecAivazis commented 1 year ago

👋 Hey @macmillen!

There are already $data types exported for each fragment that contain just the shape of the fragment - does that work?

macmillen commented 1 year ago

hey @AlecAivazis i'm already using these as you can see in the example code (Widget$data). the thing is that i want to have the pure parent type with the fragments being the $data types without me having to do these crazy type acrobatics

AlecAivazis commented 1 year ago

Ah! I understand now. Sorry for not reading your message more carefully.

I think I am in favor of your second option to create a type helper. Would you be willing to submit a PR that adds a FlattenSelection utility type that does exactly that?

macmillen commented 1 year ago

let's say we want to transform this type:

export type MyDashboard$result = {
    readonly dashboard: {
        readonly tiles: ({
            readonly id: string;
            readonly widget: {
                readonly " $fragments": {
                    Widget: {};
                };
            };
        })[];
    };
};

into this:

export type MyDashboard$result = {
    readonly dashboard: {
        readonly tiles: ({
            readonly id: string;
            readonly widget: Widget$data;
        })[];
    };
};

actually i don't think it's possible to create a type helper because in this example it would need to be aware of the Widget$data to replace the widget fragment type with Widget$data. i'm not sure but i think the only solution is to generate the types

AlecAivazis commented 1 year ago

I think we could pull it off by generating a type that maps those strings to the $data types and then index it in the helper using the string in the $fragments key. That being said, i'm not sure its worth the effort: using MyQuery$whatever is pretty much the same as Whatever<MyQuery> and the codebase already has all of the logic to generate the definition.

I'm good with whichever option you prefer

macmillen commented 1 year ago

I think the type generation would be easier than writing the type helper but i don't think i am able to write a PR for that unfortunately

V-ed commented 12 months ago

EDIT :

Turns out simply adding defaultFragmentMasking: 'disable', to my houdini.config.js solved my issue here.

It might not be the optimal way to use GraphQL, but I'm happy that this option exist, I will be able to use fragments how I intended to until the point I decide to change my approach completely haha

Thanks to @jycouet for the pointer!


A thousand times this - currently, fragments are literally not usable in my codebase because the types are messed up.

Types generated Values provided

I'm okay with extending the type with a " $fragments" key, but at least add the fragment data to the returned type, as currently, in my example, sessionUser has no keys in typescript, yet all the data is there in the actual javascript object.


I do have to say that I don't use the stores as "usual" per se, as I mainly use the client as server only loads. Therefore, my problem is similar in that I would need to use convoluted type acrobatics just to get the data structure, which is what I would have hoped not to do using this library.

AlecAivazis commented 2 weeks ago

I'm going to close this since its gone stale and its not the recommended pattern for Houdini. If someone runs into this issue and wants to add it, ill happily provide whatever guidance they want